我是靠谱客的博主 可耐蛋挞,最近开发中收集的这篇文章主要介绍使用链表定义堆栈,实现pop,push,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

首先我要说明的是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;
}


运行结果:
使用链表定义堆栈,实现pop,push


最后

以上就是可耐蛋挞为你收集整理的使用链表定义堆栈,实现pop,push的全部内容,希望文章能够帮你解决使用链表定义堆栈,实现pop,push所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部