数据结构实现(六):链表栈(C++版)
1. 概念及基本框架
通过第五节,我们知道链表虽然整体的操作时间复杂度是 O(n) 级别的,但是如果只对头结点进行操作,那么时间复杂度是 O(1) 级别的,这很类似于栈(单口容器)的操作。
在第二节中,我们利用 数组 实现了 栈 这种数据结构。当然,栈也可以通过 链表 来实现。下面通过链表来实现 链表栈 。
链表栈的结构如上图所示,链表栈有着栈的基本特性:
1.栈 有 栈顶 和 栈底 两端。
2.入栈 和 出栈 操作只能从 栈顶 进行。
3.后 入栈 的先 出栈 ,即 后进先出(Last In First Out),LIFO 。
与数组栈类似,依旧使用由 纯虚函数 构成的 抽象类 作为一个接口来定义栈的基本操作。具体代码如下:
template <class T>
class Stack{
public:
virtual int size() = 0;
virtual bool isEmpty() = 0;
virtual void print() = 0;
//入栈操作
virtual void push(T num) = 0;
//出栈操作
virtual void pop() = 0;
//获得栈顶元素
virtual T peek() = 0;
};
下面只需要通过继承 抽象类,并且重写 纯虚函数 ,就可以完成 链表栈 的实现。链表栈类的框架如下:
template <class T>
class LinkedListStack : public Stack<T>{
public:
LinkedListStack(){}
...
private:
LinkedList<T> list;
};
这个类内部定义一个链表类对象,为了保护数据,把它放在 private 部分。因为 LinkedListStack 类包含了 LinkedList 类,所以构造函数 LinkedListStack 会自动调用 LinkedList 的构造函数。为了兼容更多类型,这里使用了泛型的概念。
2. 基本操作程序实现
2.1 入栈操作
template <class T>
class LinkedListStack : public Stack<T>{
public:
...
//入栈操作
void push(T num){
list.addFirst(num);
}
...
};
入栈操作使用了链表的增加第一个元素的操作来实现。
2.2 出栈操作
template <class T>
class LinkedListStack : public Stack<T>{
public:
...
//出栈操作
void pop(){
list.removeFirst();
}
...
};
出栈操作使用了链表的删除第一个元素的操作来实现。
2.3 查找操作
template <class T>
class LinkedListStack : public Stack<T>{
public:
...
//获得栈顶元素
T peek(){
return list.get(0);
}
...
};
因为栈只能获得栈顶元素,所以这里的查找操作也非常简单。
2.4 其他操作
template <class T>
class LinkedListStack : public Stack<T>{
public:
...
int size(){
return list.size();
}
bool isEmpty(){
return list.isEmpty();
}
void print(){
cout << "LinkedListStack: ";
cout << "Size = " << list.size() << endl;
cout << "top ";
for (int i = 0; i < list.size(); ++i){
cout << list.get(i) << "->";
}
cout << "NULL" << endl;
}
...
};
3. 算法复杂度分析
3.1 入栈操作
函数 | 最坏复杂度 | 平均复杂度 |
---|---|---|
push | O(1) | O(1) |
3.2 出栈操作
函数 | 最坏复杂度 | 平均复杂度 |
---|---|---|
pop | O(1) | O(1) |
3.3 查找操作
函数 | 最坏复杂度 | 平均复杂度 |
---|---|---|
peek | O(1) | O(1) |
总体情况:
操作 | 时间复杂度 |
---|---|
增 | O(1) |
删 | O(1) |
查 | O(1) |
因为都是针对第一个元素的操作,链表栈操作都是 O(1) 级别的时间复杂度,而且相较数组栈而言,省去了扩容(缩容)操作。
注:这里并没有改的操作,如果更改,需要先出栈,再入栈。
4. 完整代码
链表类 代码:
#ifndef __LINKEDLIST_H__
#define __LINKEDLIST_H__
using namespace std;
template <class T>
class Node{
public:
Node(T num = NULL, Node *next = NULL){
m_data = num;
this->next = next;
}
public:
T m_data;
Node *next;
};
template <class T>
class LinkedList{
public:
LinkedList(){
head.m_data = NULL;
head.next = NULL;
m_size = 0;
}
int size(){
return m_size;
}
bool isEmpty(){
return m_size == 0;
}
void print(){
cout << "LinkedList: ";
cout << "Size = " << m_size << endl;
Node<T> *node = head.next;
while(node){
cout << node->m_data << "->";
node = node->next;
}
cout << "NULL" << endl;
}
//增加操作
void add(int index, T num);
void addFirst(T num);
void addLast(T num);
//删除操作
T remove(int index);
T removeFirst();
T removeLast();
void removeElement(T num);
//修改操作
void set(int index, T num);
//查找操作
T get(int index);
T getFirst();
T getLast();
bool contains(T num);
private:
Node<T> head;
int m_size;
};
template <class T>
void LinkedList<T>::add(int index, T num){
if (index < 0 || index > m_size){
cout << "添加位置非法!" << endl;
return;
}
Node<T> *node = &head;
for (int i = 0; i < index; ++i, node = node->next);
node->next = new Node<T>(num, node->next);
m_size++;
}
template <class T>
void LinkedList<T>::addFirst(T num){
add(0, num);
}
template <class T>
void LinkedList<T>::addLast(T num){
add(m_size, num);
}
template <class T>
T LinkedList<T>::remove(int index){
if (index < 0 || index >= m_size){
cout << "删除位置非法!" << endl;
return NULL;
}
Node<T> *node = &head;
for (int i = 0; i < index; ++i, node = node->next);
Node<T> *p = node->next;
T res = p->m_data;
node->next = p->next;
delete p;
m_size--;
return res;
}
template <class T>
T LinkedList<T>::removeFirst(){
return remove(0);
}
template <class T>
T LinkedList<T>::removeLast(){
return remove(m_size - 1);
}
template <class T>
void LinkedList<T>::removeElement(T num){
Node<T> *node = &head;
Node<T> *p;
while(node){
p = node->next;
if (p->m_data == num){
node->next = p->next;
delete p;
m_size--;
return;
}
node = p;
}
}
template <class T>
void LinkedList<T>::set(int index, T num){
Node<T> *node = head.next;
for (int i = 0; i < index; ++i, node = node->next);
node->m_data = num;
}
template <class T>
T LinkedList<T>::get(int index){
if (index < 0 || index >= m_size){
cout << "访问位置非法!" << endl;
return NULL;
}
Node<T> *node = head.next;
for (int i = 0; i < index; ++i, node = node->next);
return node->m_data;
}
template <class T>
T LinkedList<T>::getFirst(){
return get(0);
}
template <class T>
T LinkedList<T>::getLast(){
return get(m_size - 1);
}
template <class T>
bool LinkedList<T>::contains(T num){
Node<T> *node = head.next;
while(node){
if (node->m_data == num){
return true;
}
node = node->next;
}
return false;
}
#endif
抽象类 接口代码:
#ifndef __STACK_H__
#define __STACK_H__
template <class T>
class Stack{
public:
virtual int size() = 0;
virtual bool isEmpty() = 0;
virtual void print() = 0;
//入栈操作
virtual void push(T num) = 0;
//出栈操作
virtual void pop() = 0;
//获得栈顶元素
virtual T peek() = 0;
};
#endif
链表栈 代码:
#ifndef __LINKEDLISTSTACK_H__
#define __LINKEDLISTSTACK_H__
#include "LinkedList.h"
#include "Stack.h"
template <class T>
class LinkedListStack : public Stack<T>{
public:
LinkedListStack(){}
int size(){
return list.size();
}
bool isEmpty(){
return list.isEmpty();
}
void print(){
cout << "LinkedListStack: ";
cout << "Size = " << list.size() << endl;
cout << "top ";
for (int i = 0; i < list.size(); ++i){
cout << list.get(i) << "->";
}
cout << "NULL" << endl;
}
//入栈操作
void push(T num){
list.addFirst(num);
}
//出栈操作
void pop(){
list.removeFirst();
}
//获得栈顶元素
T peek(){
return list.get(0);
}
private:
LinkedList<T> list;
};
#endif