对象的集合--栈 ,使用链表来实现

1.之前的一篇文章里面写的是使用vector或者原始数组来实现一个栈,这篇文章则是使用链表来实现一个栈。


2.使用链表来实现栈的好处在于:

i.push 和pop 操作 都是与链表长度无关的。

ii.所需的空间总是跟所要处理的数据的大小成正比。


3.实现:


list.hpp

#ifndef LIST_HPP
#define LIST_HPP

#include <iostream>
#include <string>
using namespace std;

template <typename T>
class MyList 
{
public:
	MyList();                  //构造函数,只用把头指针置为空就行
	~MyList();
	void insert(T item);        //向链表里面插入数据,在表头实现插入
	T deleteFirst();		   //删除第一个节点
	bool isEmpty();
	unsigned int size();

private:
	class Node {         //内部类,节点类。
	public:
		Node(T item) : data(item), next(NULL){}
		~Node(){}
		T data;              //数据
		Node* next;			//链接
	};

	Node* head;           //链表的头指针
};

template <typename T>
MyList<T>::MyList() : head(NULL)
{
}

template <typename T>
MyList<T>::~MyList(){}

template <typename T>
void MyList<T>::insert(T item)
{
	if (isEmpty())     //如果链表为空,新建一个节点,并让头指针指向这个节点。
	{
		Node* current = new Node(item);
		head = current;
	}
	else              //如果链表不为空,新建一个节点,并让next的值为当前的头指针的值,并把head重新赋值
	{
		Node* newNode = new Node(item);
		newNode->next = head;
		head = newNode;
	}
}

template <typename T>
T MyList<T>::deleteFirst()
{
	if(isEmpty())          //如果链表为空,那么输出提示信息,返回0;
	{
		cout << "The data is empty" << endl;
	}

	else
	{
		Node* deleteNode = head;
		T data = deleteNode->data;
		head = head->next;       //修改head的指向
		delete deleteNode;      //释放内存
		return data;
	}

	return 0;
}


//模版特化,针对string类型,模版这一块掌握不是很好,可以考虑去模版或者全特化
template <>
string MyList<string>::deleteFirst()
{
	string data("");
	if(isEmpty())
	{
		cout << "The data is empty" << endl;
	}

	else
	{
		Node* deleteNode = head;
		data = deleteNode->data;
		head = head->next;
		delete deleteNode;
	}

	return data;
}

//判空函数
template <typename T>
bool MyList<T>::isEmpty()
{
	return head == NULL;
}

template <typename T>
unsigned int MyList<T>::size()
{
	unsigned int size = 0;
	while(head != NULL)
	{
		size++;
		head = head->next;
	}
	return size;
}

#endif

stack.hpp

#ifndef STACK_HPP
#define STACK_HPP

#include "list.hpp"

template <typename T>
class MyStack
{
public:
	MyStack();
	~MyStack();
	T pop();
	void push(T item);
	bool isEmpty();
private:
	MyList<T> dataList;
};

template <typename T>
MyStack<T>::MyStack() : dataList(){}

template <typename T>
MyStack<T>::~MyStack(){}

template <typename T>
T MyStack<T>::pop()
{
	return dataList.deleteFirst();         //pop操作直接调用list 的删除头节点的函数
}

template <typename T>
void MyStack<T>::push(T item)
{
	dataList.insert(item);                 //push操作直接调用list的在表头添加节点的函数
}

template <typename T>
bool MyStack<T>::isEmpty()
{
	return dataList.isEmpty();
}


#endif


main.cpp


#include "stack.hpp"

int main(int argc, char** argv)
{
	MyStack<string> myStack;

	for (int i = 0; i != 10; ++i)
	{
		myStack.push(std::to_string(i) + 'a');
	}

	while (!myStack.isEmpty())
	{
		cout << myStack.pop() << " ";
	}

	cout << endl;
	return 0;
}


4.总结:

(1)我们使用链表来代替数组当做栈的内部数据结构的好处有很多:省去了数组的新申请内存和移动数据的操作,使得push和pop的操作所需的时间跟已经在栈里面的元素的多少没有关系,仅使用单链表即可完成栈的构造,因为我们的链表只用在表头进行操作,而不会设计到其它地方的修改。

(2)在使用了模版之后,我们可以处理更多的类型,这就极大地提升了我们的效率。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值