您的位置:首页 > 运维架构

使用链表定义堆栈,实现pop,push

2017-07-03 13:43 162 查看
首先我要说明的是stack在标准库中是有其头文件的大家不需要自己去实现一个stack。其次实现stack可以使用动态数组或者链表两种方式,如果大家去实现stack,我推荐大家使用动态数组。
首先让我们比较一下链表和动态数组的优缺点吧。
链表:
优点:
1,访问最后一个节点的时间是一样的,0(n)
2,插入任何一个结点的时间是一样的
缺点:
1,处理小规模的数据开销很大,因为需要不断的申请地址

2,即便是处理大的数据,也不见得比动态数组快。因为内存读到cache中的时候,会将hit的数据周围都会读进cache中。所以如果地址不是连续的,hit这个内存的时间其实是挺高的。
动态数组:
优点:
1,数组在任何节点的访问时间都是o(1),因为可以通过下标直接访问。
2,在内存被hit的时候,数组周围的数据都被缓存,所以访问时间上也会减少
缺点:
如果实现方法不好,会导致很大的重复操作,例如:

每一次push一个数据,都申请一个将数组大小+1的地址。然后转移数据,清除之前留下的数据。这是一种很不好的实现方法。

实际上,vs2010里面自带的stack、实现方式是通过protected中的成员变量deque来实现puck和pop的。
而deque其实是双向队列,该空间中每个元素都是指针,指向另一段较大的区域,这个区域称为缓冲区,缓冲区用来保存deque中的数据。因此deque在随机访问和遍历数据会比动态数组慢。

所以综上所述,如果一定要自己实现stack的话,用动态数组更好。
但是这里我用的是链表去实现stack,也只是为了演示作用。
代码中的我已经运行过了,代码的注释也很多我相信大家都能够看的很明白。

#include "stdafx.h"
#include
#include
using namespace std;
template
class my_stack
{
private:
//这里私有定义节点,里面有两个变量:数据和指向下一个节点的指针
struct my_data
{
my_data *next;
Type data;
};
//根节点要重要保护,因为这是链表所有的内容都要通过根节点去查找
my_data *root;
public:
//构造函数将root赋值为nullptr

//注意这里是nullptr不是null,这是C++0X新的内容,希望大家在定义空指针的时候使用nullptr,这样其实更符合规范
my_stack():root(nullptr){}

void push(Type new_data)//插入数据
{
if(root==nullptr)//如果链表内部是空的
{

//注意这里要用try,catch,因为这里涉及内存的分配,很有可能会报出异常,所以要做好内存处理,否则会产生内存泄露
try
{
root=new my_data;
root->data=new_data;
root->next=nullptr;
}
catch(exception
&e)//std::exception用来捕捉九大异常,e.what()用来显示异常的错误信息
{
if(root!=nullptr)
{
delete root;
root=nullptr;
cout<<e.what()<<endl;
}
}
}
else//如果插入时链表不为空
{

my_data *old_ptr=root;

while(old_ptr->next!=nullptr)old_ptr=old_ptr->next;//将插入位置移到链表的末端
try
{

old_ptr->next=new my_data;
old_ptr->next->data=new_data;
old_ptr->next->next=nullptr;
}
catch (exception &e)
{
if(old_ptr->next!=nullptr)
{
delete (old_ptr->next);
old_ptr->next=nullptr;
cout<<e.what()<<endl;
}
}

}
}
bool pop(Type&
new_data)//这里使用bool返回值也是检测返回值是否正确的一个方法,因为pop的时候有很大的可能链表内部已经为空了,这时候就要返回一个提示。
{
if(root==nullptr)//如果链表内部已经为空了
{
cout<<"the stack is empty now."<<endl;
return false;

}
else if(root->next==nullptr)//如果只有根节点这一个数据
{
new_data=root->data;
delete root;
root=nullptr;
return true;
}
else//如果链表内部有多个节点
{

try
{
my_data *old_ptr=root;
my_data *new_ptr=root;

while(old_ptr->next!=nullptr)
{
new_ptr=old_ptr;
old_ptr=old_ptr->next;
}
new_data=old_ptr->data;
delete old_ptr;
new_ptr->next=nullptr;
return true;
}
catch(exception &e)
{
cout<<e.what()<<endl;
return false;
}
}
}

~my_stack()//析构函数用来回收所有内存
{
my_data *this_data;
this_data=root;
while(root!=nullptr)
{
this_data=root;
root=root->next;
delete this_data;
}
}
};

int main()
{
my_stack my_stack1;
my_stack1.push(1);
my_stack1.push(2);
my_stack1.push(3);
my_stack1.push(4);
my_stack1.push(5);
int new_data;
while(my_stack1.pop(new_data))
{
cout<<"pop data "<<new_data<<endl;
}
return 0;
}

运行结果:


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: