堆栈——链表实现(链式栈)(C++版)

定义

前面说了用数组(顺序表)实现堆栈,用数组实现堆栈这种方法既高效又简单,但是在描述两个以上的堆栈时,虽然可以提高空间利用率,但是却增加了Add操作的时间复杂度。除此之外,也可以使用链表的方式来实现一个堆栈来解决上述问题,这种方式虽然使每个元素多了一个指针的空间,但是却使时间复杂度得到了有效的降低。
一般来讲,我们将链表的左端作为top指针所指向的位置,这样可以降低编码的复杂性和操作的时间复杂性。因为将链表右端作为top指针,那么出栈入栈操作的时间复杂度将为O(n),而左端则仅仅为O(1)。

类的描述

类的描述和链表很相似,只不过在类中的方法上有区别,由于堆栈的特殊性(LIFO),其插入和删除操作都有只在链表的左端进行,具体的代码如下:

template<class T>
class Stack;//堆栈类的声明

template<class T>
class Node{ //节点类
	friend class Stack<T>; //定义友元类
	private:
		T data; //数据域
		Node<T>* next;//指针域
		Node(){}//构造方法
}

template<class T>
class Stack{ //堆栈类的实现
	public:
		Stack();//构造方法
		~Stack();//析构函数
		void Push(const T& x);//入栈
		T Pop();//出栈
		T Top()const;//查看栈顶数据
		bool IsEmpty()const;//判断栈是否为空
		bool IsFull()const;//判断栈是否已满
	private:
		Node<T>* top; //栈顶指针
}
构造方法的实现

构造方法中只需要对各个变量进行初始化即可。

template<class T>
Stack<T>::Stack(){
	top=NULL;
}
析构函数的实现

析构函数就是要释放链表中的各个节点。

template<class T>
Stack<T>::~Stack(){
	Node<T>* temp=NULL;
	while(top!=NULL){
		temp=top->next;
		delete top;
		top=temp;
	}
}
入栈(Push)的实现

入栈的过程如下:(说明:first即为top指针)
在这里插入图片描述
如上图,有一个节点pt,现在想要进入到first的链表,首先,保存first的值,用pfn来保存,然后让first指向新的节点pt,然后再让pt的指针域保存first原来指向的值pfn即可。如此循环,这样连续插入两个节点的过程如下:
在这里插入图片描述
在这里插入图片描述
代码实现参考如下:

template<class T>
void Stack<T>::Push(const T& x){
	if(!IsFull()){ //判断链表是否已满
		Node<T>* pt = new Node<T>(); //创建节点
		pt->data = x; //指定数据域数值
		Node<T>* temp = top;
		top = pt;
		pt->next = temp; //至此,入栈完成
	}else{ //栈已满,抛出异常
		throw "the stack is full!";
	}
}
出栈(Pop)的实现

出栈的过程如下:
首先,用一个临时指针保存top指针存储的节点。
在这里插入图片描述
然后右移top指针,即top=top->next;如下:
在这里插入图片描述
然后将temp中节点的数据取出,销毁temp节点即可。具体代码参考如下:

template<class T>
T Stack<T>::Pop(){
	if(!IsEmpty()){ //栈不为空
		Node<T>* temp = top; //保存top指针现有的节点
		top = top->next;//右移top指针
		T temp_data = temp->data;//取出temp节点中的数据
		delete temp;//释放temp节点的空间
		return temp_data; //返回数据
	}else{ //栈为空
		throw "the stack is empty!";
	}
}
查看(top)栈顶数据的实现

只需要返回top指针指向的节点的数据即可。具体代码参考如下:

template<class T>
T Stack<T>::Top()const{
	return top->data;
}
判断栈是否已空和已满

判断栈是否已空很简单,只需要看top的值是否为NULL即可。代码参考如下:

template<class T>
bool Stack<T>::IsEmpty()const{
	return top==NULL;
}

判断栈是否为空,则需要进行异常检测,判断是否还有内存可以分配,具体代码参考如下:

template<class T>
bool Stack<T>::IsFull()const{
	try{
		Node<T>* p = new Node<T>(); //表名是否还能创建节点,如果不能,new引发NoMem异常。
		delete p;//删除创建的节点
		return false;//能够创建节点,栈未满
	}catch(exception e){//引发NoMem异常,说明内存已满
		return true;
	}
}
测试程序
int main(){
    Stack<int> mystack; //这里mystack不能加“()”符号
    cout<<mystack.IsFull()<<endl;
    cout<<mystack.IsEmpty()<<endl;
    cout<<"入栈"<<endl;
    mystack.Push(50);
    mystack.Push(25);
    mystack.Push(30);
    mystack.Push(31);
    mystack.Push(45);
    mystack.Push(0);
    cout<<mystack.IsFull()<<endl;
    cout<<mystack.IsEmpty()<<endl;
    cout<<"....."<<endl;
    cout<<"出栈"<<endl;
    cout<<"data is "<<mystack.Pop()<<endl;
    cout<<"data is "<<mystack.Pop()<<endl;
    cout<<"data is "<<mystack.Pop()<<endl;
    cout<<"data is "<<mystack.Pop()<<endl;
    cout<<"data is "<<mystack.Pop()<<endl;
    cout<<"data is "<<mystack.Top()<<endl;
    cout<<"data is "<<mystack.Pop()<<endl;
    cout<<mystack.IsFull()<<endl;
    cout<<mystack.IsEmpty()<<endl;
    return 0;
}
  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值