栈的链表实现

栈的抽象类

template <class Type>
class stackADT
{
public:
	virtual void initializeStack() = 0;
	virtual bool isEmptyStack()const = 0;
	virtual bool isFullStack()const = 0;
	virtual void push(const Type&) = 0;
	virtual void pop() = 0;
	virtual Type top()const = 0;
};

抽象类只给出最基本的方法,没有函数实现。

节点

template<class Type>
struct node
{
	Type info;
	node<Type>* next;
};

用struct定义节点的好处在于不用管构造函数,结构体里只放变量,而且这里struct也是个模板,可以适应不同的元素类型。

链栈类

template<class Type>
class linkStack :public stackADT<Type>
{
public:
	void initializeStack();
	bool isEmptyStack()const;
	bool isFullStack()const;
	void push(const Type&);
	void pop();
	Type top()const;
	linkStack();
	linkStack(const linkStack<Type>&);
	~linkStack();
	const linkStack<Type>& operator=(const linkStack<Type>&);
private:
	node<Type>* stackTop;
	void copyStack(const linkStack<Type>&);
};

链栈继承了抽象栈的基本方法,我们要表示一个链栈只需要一个指向栈顶的指针就行了。

成员函数表

函数名函数功能
void isEmptyStack()const判断栈是否为空
void isFullStack()const判断栈是否已经满
void initializeStack()初始化栈
void pop()弹出一个元素
void push(const Type&)将元素压入栈中
Type top()const返回栈顶元素
linkStack()构造函数
void copyStack(const linkStack&)实现栈的复制操作
linkStack(const linkStack&)拷贝构造函数
~linkStack()析构函数
const linkStack& operator=(const linkStack&)重载赋值符

成员函数实现

linkStack()

对于一个类而言我们首先要考虑的就是其构造函数如何设计,第一个问题就来了,到底要不要在构造函数生成节点?并不需要,这和数组实现的栈不同,数组栈构造函数会开辟一段内存,而链栈只要让栈顶指针为空就好了。

代码如下:

template<class Type>
linkStack<Type>::linkStack()
{
	stackTop = nullptr;
}

void isEmptyStack()const

判断链栈是否为空很简单,和数组栈类似,数组栈是看栈元素个数是否为0,链栈则是看栈顶指针是否为空。

代码如下:

template<class Type>
bool linkStack<Type>::isEmptyStack()const
{
	return stackTop == nullptr;
}

void isFullStack()const

对于链栈来说理论上是永远不会满的,除非电脑内存不够了,这时会自动报错,因此返回值永远是0。

代码如下:

template<class Type>
bool  linkStack<Type>::isFullStack()const
{
	return 0;
}

void initializeStack()

链栈的初始化要分两种情况,第一种就是栈中有节点存在,这时就要依次释放节点的内存,然后把栈顶指针置为空。另外一种就是栈中无节点,由于构造函数已经把栈顶指针置为空,所以无需进行操作。不像数组栈初始化那么简单只需要把表示栈中元素个数的变量置为0就可以了。

代码如下:

template<class Type>
void linkStack<Type>::initializeStack()
{
	while (stackTop)
	{
		node<Type>* temp = stackTop;
		stackTop = stackTop->next;
		delete temp;
	}
}

void pop()

链栈弹出一个节点需要释放该节点的内存,然后让栈顶指针指向后一个节点就可以了,但是栈为空的情况要额外考虑,栈为空就在控制台输出提示信息。

代码如下:

template<class Type>
void linkStack<Type>::pop()
{
	if (isEmptyStack())
	{
		cout << "The stack is empty,cannot pop" << endl;
	}
	else
	{
		node<Type>* temp;
		temp = stackTop;
		stackTop = stackTop->next;
		delete temp;
	}
}

void push(const Type&)

将元素压入栈中,这里得考虑一个点那就是我们到底是把一个节点作为push的输入还是把元素作为push的输入,对于使用者来说我才不管你这个数据结构内部是怎么写的,链栈也好,数组栈也罢其作为栈的功能都是一样的,只不过实现方式不同,那么对于使用者来说有的肯定是元素类型,如果还要自己建立一个node那不是很麻烦了,所以我们这里把元素直接作为输入。
因为压入栈中的是元素,所以我们得新建一个节点,然后把元素放入节点中,再让该节点变成栈的栈顶节点。链栈有个好处就是压栈不用考虑栈满的情况。

代码如下:

template<class Type>
void linkStack<Type>::push(const Type& info)
{
	node<Type>* newNode = new node<Type>;
	newNode->info = info;
	newNode->next = stackTop;
	stackTop = newNode;
}

Type top()const

同push函数,top函数的不是返回节点的地址而是直接返回元素,这与使用者的期望是符合的,top函数也需要做异常处理,因为该函数是有返回值的,所以一旦遇到空栈的情况我们就要终止程序,而不能仅仅在控制台上输出异常信息。
函数实现很简单,直接返回栈顶指针的元素就行了。

代码如下:

template<class Type>
Type linkStack<Type>::top()const
{
   assert(!isEmptyStack());
   return stackTop->info;
}

void copyStack(const linkStack&)

这个函数的功能就是实现链栈的拷贝,你也许会问这不是拷贝构造函数要解决的问题吗?实际上拷贝构造函数内会调用该函数,在这里触发拷贝构造函数只有两种情况,即链栈作为函数的输入或者输出参数时,而第三种情况的处理则丢给了=运算符重载。
拷贝过程首先要判断当前链栈是否为空,若非空则要将栈初始化。然后看被拷贝的栈是否为空,如果空则令当前栈的栈顶指针为空;否则进入拷贝过程,我们设置三个指针,其中两个用来推进拷贝过程,指向当前拷贝与被拷贝的节点,另外一个则用来生成新节点。我们不要立马进入循环,注意此时栈顶指针是空的,所以我们先要拷贝第一个节点,让栈顶指针指向该节点,然后就可以进入循环了不断拷贝了。

代码如下:

template<class Type>
void linkStack<Type>::copyStack(const linkStack<Type>& otherStack)
{
	if (stackTop != nullptr)
	{
		initializeStack();
	}
	if(otherStack.isEmptyStack())
	{
		stackTop=nullptr;
	}
	else
	{
		stackTop = new node<Type>;
		stackTop->info = otherStack.stackTop->info;
		node<Type>* temp, * otherTemp;
		temp = stackTop;
		otherTemp = otherStack.stackTop->next;
		while (otherTemp)
		{
			node<Type>* newNode = new node<Type>;
			newNode->info = otherTemp->info;
			temp->next = newNode;
			temp = temp->next;
			otherTemp = otherTemp->next;
		}
		temp->next = nullptr;
	}
}

linkStack(const linkStack&)

拷贝构造函数,因为这里拷贝构造函数只在函数输入和输出的备份操作才会触发,所以是不会触发构造函数的,也就是说栈顶指针是个野指针,所以在拷贝构造函数中我们要把栈顶指针置为空,然后调用copyStack函数就行了。

代码如下:

template<class Type>
linkStack<Type>::linkStack(const linkStack<Type>& otherStack)
{
	stackTop = nullptr;
	copyStack(otherStack);
}

~linkStack()

一旦涉及到动态内存分配,析构函数就要释放内存,直接调用初始化函数即可。

代码如下:

template<class Type>
linkStack<Type>::~linkStack()
{
	initializeStack();
}

const linkStack& operator=(const linkStack&)

重载=运算符需要注意的一点就是要避免自我赋值,然后直接调用copyStack函数即可

代码如下:

template<class Type>
const linkStack<Type>& linkStack<Type>::operator=(const linkStack<Type>& otherStack)
{
	if (this != &otherStack)      //避免自我复制
		copyStack(otherStack);
	return *this;
}

全部代码

stackADT.h

template <class Type>
class stackADT
{
public:
	virtual void initializeStack() = 0;
	virtual bool isEmptyStack()const = 0;
	virtual bool isFullStack()const = 0;
	virtual void push(const Type&) = 0;
	virtual void pop() = 0;
	virtual Type top()const = 0;
};

linkStack.h

#include<iostream>
#include "stackADT.h"
#include<string>
#include<cassert>
using namespace std;
template<class Type>
struct node
{
	Type info;
	node<Type>* next;
};
template<class Type>
class linkStack :public stackADT<Type>
{
public:
	void initializeStack();
	bool isEmptyStack()const;
	bool isFullStack()const;
	void push(const Type&);
	void pop();
	Type top()const;
	linkStack();
	linkStack(const linkStack<Type>&);
	~linkStack();
	const linkStack<Type>& operator=(const linkStack<Type>&);
private:
	node<Type>* stackTop;
	void copyStack(const linkStack<Type>&);
};
template<class Type>
linkStack<Type>::linkStack()
{
	stackTop = nullptr;
}
template<class Type>
void linkStack<Type>::initializeStack()
{
	while (stackTop)
	{
		node<Type>* temp = stackTop;
		stackTop = stackTop->next;
		delete temp;
	}
}

template<class Type>
bool linkStack<Type>::isEmptyStack()const
{
	return stackTop == nullptr;
}

template<class Type>
bool  linkStack<Type>::isFullStack()const
{
	return 0;
}

template<class Type>
void linkStack<Type>::push(const Type& info)
{
	node<Type>* newNode = new node<Type>;
	newNode->info = info;
	newNode->next = stackTop;
	stackTop = newNode;
}

template<class Type>
void linkStack<Type>::pop()
{
	if (isEmptyStack())
	{
		cout << "The stack is empty,cannot pop" << endl;
	}
	else
	{
		node<Type>* temp;
		temp = stackTop;
		stackTop = stackTop->next;
		delete temp;
	}
}

template<class Type>
Type linkStack<Type>::top()const
{
	assert(!isEmptyStack());
	return stackTop->info;
}

template<class Type>
void linkStack<Type>::copyStack(const linkStack<Type>& otherStack)
{
	if (stackTop != nullptr)
	{
		initializeStack();
	}
	if (otherStack.isEmptyStack())
	{
		stackTop = nullptr;
	}
	else
	{
		stackTop = new node<Type>;
		stackTop->info = otherStack.stackTop->info;
		node<Type>* temp, * otherTemp;
		temp = stackTop;
		otherTemp = otherStack.stackTop->next;
		while (otherTemp)
		{
			node<Type>* newNode = new node<Type>;
			newNode->info = otherTemp->info;
			temp->next = newNode;
			temp = temp->next;
			otherTemp = otherTemp->next;
		}
		temp->next = nullptr;
	}
}

template<class Type>
linkStack<Type>::linkStack(const linkStack<Type>& otherStack)
{
	stackTop = nullptr;
	copyStack(otherStack);
}

template<class Type>
const linkStack<Type>& linkStack<Type>::operator=(const linkStack<Type>& otherStack)
{
	if (this != &otherStack)
		copyStack(otherStack);
	return *this;
}

template<class Type>
linkStack<Type>::~linkStack()
{
	initializeStack();
}

主函数(测试)

#include "linkStack.h"
#include<iostream>
using namespace std;
void testCopyConstructor(linkStack<int> otherStack);
int main()
{
	linkStack<int> stack;
	linkStack<int> copyStack;
	linkStack<int> dummyStack;
	stack.initializeStack();
	stack.push(23);
	stack.push(45);
	stack.push(38);
	copyStack.push(11);
	copyStack = stack; //copy stack into copyStack
	cout << "The elements of copyStack: ";
	while (!copyStack.isEmptyStack()) //print copyStack
	{
		cout << copyStack.top() << " ";
		copyStack.pop();
	}
	cout << endl;
	copyStack = stack;
	testCopyConstructor(stack); //test the copy constructor
	if (!stack.isEmptyStack())
		cout << "The original stack is not empty." << endl
		<< "The top element of the original stack: "
		<< copyStack.top() << endl;
	dummyStack = stack; //copy stack into dummyStack
	cout << "The elements of dummyStack: ";
	while (!dummyStack.isEmptyStack()) //print dummyStack
	{
		cout << dummyStack.top() << " ";
		dummyStack.pop();
	}
	cout << endl;
	return 0;

}
void testCopyConstructor(linkStack<int> otherStack)
{
	if (!otherStack.isEmptyStack())
		cout << "otherStack is not empty." << endl
		<< "The top element of otherStack: "
		<< otherStack.top() << endl;
}

[[栈的数组实现]]

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值