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

資料結構實現(二):陣列棧(C++版)

資料結構實現(二):陣列棧(C++版)

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 ArrayStack : public Stack<T>{
public:
	ArrayStack(int len = initialLen){
		Array<
T> *p= new Array<T>(len); arr = p; } ... private: Array<T> *arr; };

這個類內部定義一個動態陣列類物件,為了保護資料,把它放在 private 部分,建構函式 ArrayStack 底層呼叫的就是 Array 的建構函式。使用者在建構函式中也可以指定棧的大小。(預設是10)為了相容更多型別,這裡使用了泛型的概念。

2. 基本操作程式實現

2.1 入棧操作

template <class T>
class ArrayStack : public Stack<T>{
public:
	...
	//入棧操作
	void push(T num){
		arr->addLast(num);
	}
	...
};

入棧操作使用了動態陣列的增加最後一個元素的操作來實現。這裡動態陣列內部已經提供了擴容操作。

2.2 出棧操作

template <class T>
class ArrayStack : public Stack<T>{
public:
	...
	//出棧操作
	void pop(){
		arr->removeLast();
	}
	...
};

出棧操作使用了動態陣列的刪除最後一個元素的操作來實現。這裡動態陣列內部已經提供了縮容操作。

2.3 查詢操作

template <class T>
class ArrayStack : public Stack<T>{
public:
	...
	T peek(){
		return arr->get(arr->size() - 1);
	}
	...
};

因為棧只能獲得棧頂元素,所以這裡的查詢操作也非常簡單。

2.4 其他操作

template <class T>
class ArrayStack : public Stack<T>{
public:
	...
	int size(){
		return arr->size();
	}
	bool isEmpty(){
		return arr->size() == 0;
	}
	void print(){
		cout << "ArrayStack: ";
		cout << "Size = " << arr->size() << endl;
		cout << '[';
		for (int i = 0; i < arr->size(); ++i){
			cout << arr->get(i);
			if (i != arr->size() - 1){
				cout << ',';
			}
		}
		cout << "]top" << endl;
	}
	...
};

3. 演算法複雜度分析

3.1 入棧操作

函式 最壞複雜度 平均複雜度
push O(1+n) = O(n) O(1+1) = O(1)

最壞複雜度 O(1+n) 中第一個 1 是指元素移動操作,第二個 n 是指動態陣列中的 resize 函式,以下同理。
入棧可能會引發擴容操作,平均而言,每增加 n 個元素,會擴充套件一次,會發生 n 個元素的移動,所以平均下來是 O(1)

3.2 出棧操作

函式 最壞複雜度 平均複雜度
pop O(1+n) = O(n) O(1+1) = O(1)

3.3 查詢操作

函式 最壞複雜度 平均複雜度
peek O(1) O(1)

總體情況:

操作 時間複雜度
O(1)
O(1)
O(1)

由此可以看出,棧操作都是 O(1) 級別的時間複雜度。
注:這裡並沒有改的操作,如果更改,需要先出棧,再入棧。

4. 完整程式碼

動態陣列類 程式碼:

#ifndef __ARRAY_H__
#define __ARRAY_H__

using namespace std;

const int initialLen = 10;
template <class T>
class Array{
public:
	Array(int len = initialLen){
		T *p = new T[len];
		m_data = p;
		m_capacity = len;
		m_size = 0;
	}
	int capacity(){
		return m_capacity;
	}
	int size(){
		return m_size;
	}
	void resize(int len){
		T *p = new T[len];
		for (int i = 0; i < m_size; ++i){
			p[i] = m_data[i];
		}
		delete[] m_data;
		m_data = p;
		m_capacity = len;
	}
	bool isEmpty(){
		return m_size == 0;
	}
	void print(){
		cout << "Array: ";
		cout << "Capacity = " << m_capacity << ", " << "Size = " << m_size << endl;
		cout << '[';
		for (int i = 0; i < m_size; ++i){
			cout << m_data[i];
			if (i != m_size - 1){
				cout << ',';
			}
		}
		cout << ']' << 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);
	int find(T num);
	bool contains(T num);
private:
	T *m_data;       //陣列資料
	int m_capacity;  //陣列容量
	int m_size;      //陣列大小
};

template <typename T>
void Array<T>::add(int index, T num){
	if (index < 0 || index > m_size){
		cout << "新增位置非法!" << endl;
		return;
		//throw 0;  //這裡可以使用拋異常,下面也可以
	}
	if (m_size >= m_capacity){
		resize(2 * m_capacity);
	}
	for (int i = m_size; i > index; --i){
		m_data[i] = m_data[i - 1];
	}
	m_data[index] = num;
	m_size++;
}
template <class T>
void Array<T>::addFirst(T num){
	add(0, num);
}
template <class T>
void Array<T>::addLast(T num){
	if (m_size >= m_capacity){
		resize(2 * m_capacity);
	}
	m_data[m_size] = num;
	m_size++;
}

template <class T>
T Array<T>::remove(int index){
	if (index < 0 || index >= m_size){
		cout << "刪除位置非法!" << endl;
		return NULL;
	}
	T res = m_data[index];
	m_size--;
	for (int i = index; i < m_size; ++i){
		m_data[i] = m_data[i + 1];
	}
	if (m_size < m_capacity / 4){
		resize(m_capacity / 2);
	}
	return res;
}
template <class T>
T Array<T>::removeFirst(){
	T res = m_data[0];
	remove(0);
	return res;
}
template <class T>
T Array<T>::removeLast(){
	if (m_size == 0){
		cout << "刪除位置非法!" << endl;
		return NULL;
	}
	m_size--;
	if (m_size < m_capacity / 4){
		resize(m_capacity / 2);
	}
	return m_data[m_size];
}
template <class T>
void Array<T>::removeElement(T num){
	int flag = find(num);
	if (flag != -1){
		remove(flag);
	}
}

template <class T>
void Array<T>::set(int index, T num){
	if (index < 0 || index >= m_size){
		cout << "修改位置非法!" << endl;
		return;
	}
	m_data[index] = num;
}

template <class T>
T Array<T>::get(int index){
	if (index < 0 || index >= m_size){
		cout << "訪問位置非法!" << endl;
		return NULL;
	}
	return m_data[index];
}
template <class T>
int Array<T>::find(T num){
	for (int i = 0; i < m_size; ++i){
		if (m_data[i] == num){
			return i;
		}
	}
	return -1;
}
template <class T>
bool Array<T>::contains(T num){
	for (int i = 0; i < m_size; ++i){
		if (m_data[i] == num){
			return true;
		}
	}
	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 __ARRAYSTACK_H__
#define __ARRAYSTACK_H__

#include "Array.h"
#include "Stack.h"

template <class T>
class ArrayStack : public Stack<T>{
public:
	ArrayStack(int len = initialLen){
		Array<T> *p= new Array<T>(len);
		arr = p;
	}
	int size(){
		return arr->size();
	}
	bool isEmpty(){
		return arr->size() == 0;
	}
	void print(){
		cout << "ArrayStack: ";
		cout << "Size = " << arr->size() << endl;
		cout << '[';
		for (int i = 0; i < arr->size(); ++i){
			cout << arr->get(i);
			if (i != arr->size() - 1){
				cout << ',';
			}
		}
		cout << "]top" << endl;
	}
	//入棧操作
	void push(T num){
		arr->addLast(num);
	}
	//出棧操作
	void pop(){
		arr->removeLast();
	}
	//獲得棧頂元素
	T peek(){
		return arr->get(arr->size() - 1);
	}
private:
	Array<T> *arr;
};

#endif