1. 程式人生 > >資料結構實現(六):連結串列棧(C++版)

資料結構實現(六):連結串列棧(C++版)

資料結構實現(六):連結串列棧(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