1. 程式人生 > >二、C++實現list資料結構

二、C++實現list資料結構

本文使用c++實現list資料結構,list的介面函式採用高效的實現方式,這樣一方面使我加深對資料結構的理解,另一方便可以讓我再複習複習c++,通過前幾天寫的vector資料結構的底層實現,我確實又進一步地熟悉使用C++進行程式設計,,這次寫list的實現過程中,我幾乎沒有怎麼檢視《c++prime》了哈哈,就是函式物件形式的遍歷函式的宣告格式怎麼也想不起來,後來查書才明白函式的形參其實是個類的物件,只不過這個類名要在宣告前指明,如下:

template<typename FuncClass> void traverse(FuncClass func);

list的實現包含兩個類:listNode

list,其中listNode中主要描述了list中單個節點的內部結構,包含一個data變數和兩個分別指向前節點和後節點的指標;而list類則是描述了一個list的結構及其操作,比如檢視規模大小、插入新節點、刪除節點、排序、查詢等。

listNode介面列表
操作 功能 物件
listNode() 預設建構函式  
listNode(T e, listNode<T> *p, listNode<T> *s) 建構函式,設定data,指向前後節點的指標  
~listNode 解構函式  
insertAsPred(const T& e) 在當前節點前插入一個新節點 節點
insertAsSucc(const T& e) 在當前節點後插入一個新節點 節點
list介面列表
操作 功能 物件
list() 預設建構函式,只初始化list的首尾哨兵節點  
list(std::initializer_list<T> li) 建構函式(列表初始化方式)  
list(listNode<T>* p, int n) 建構函式,拷貝指定節點及其後n個節點  
list(list<T>& li) 建構函式,拷貝另一list物件  
list(list<T>& li, Rank lr, Rank rr) 建構函式,拷貝另一list物件的指定區間  
~list() 解構函式,手動釋放哨兵及有效節點的記憶體空間  
init() list初始化時建立前後哨兵節點 列表
size() 返回list物件的規模 列表
display() 列印當前list中的所有元素 列表
first() 返回第一個有效節點的地址 列表
last() 返回最後一個有效節點的地址 列表
find(const T& e, int n, listNode<T>* p) 在節點p之前的n個長度範圍內查詢元素 列表
find(const T& e) 在整個list中查詢元素 列表
search(const T& e, int n, listNode<T>* p) 在節點p之前的n個長度範圍內查詢元素e,返回不大於此元素的最大節點的地址 有序列表
search(const T& e) 在整個list中查詢元素,返回不大於此元素的最大節點的地址 有序列表
insertAsFirst(const T& e) 插入元素作為first節點 列表
insertAsLast(const T& e) 插入元素作為last節點 列表
insertAsPred(listNode<T>* p, const T& e) 在節點P之前插入元素e 列表
insertAsSucc(listNode<T>* p, const T& e) 在節點P之後插入元素e 列表
insert(Rank r, const T& e) 在指定秩出插入元素(警告:線性複雜度) 列表
remove(listNode<T>* p) 刪除指定節點 列表
clear() 清除list內所有有效節點 列表
deduplicate() 去除list內重複元素 列表
uniquify() 去除list內重複元素 有序列表
traverse(void(*func)(T &)) 批量處理list內所有元素(函式指標方式) 列表
traverse(FuncClass func) 批量處理list內所有元素(函式物件方式) 列表
sort(listNode<T>* p, int n,int s) 排序介面彙總 列表
insertionSort() 插入排序法 列表
insertionSort(listNode<T>* p,int n) 對從p節點開始的n範圍內的節點進行排序(插入排序法) 列表
selectionSort() 選擇排序法 列表
selectionSort(listNode<T>* p, int n) 對從p節點開始的n範圍內的節點進行排序(選擇排序法) 列表
mergeSort(listNode<T>* p,int n) 對從p節點開始的n範圍內的節點進行排序(歸併排序法) 列表
過載運算子[] 下標運算子 列表
過載運算子= 賦值運算子(列表賦值方式) 列表

(1) listNode.h

#pragma once
typedef int Rank;


template<typename T> struct listNode   //節點元素模板類
{
	//成員變數
	T data;
	listNode<T> *pred, *succ;    //定義前驅和後繼指標,實現雙向連結串列

	//建構函式
	listNode() {}     //構造list前後哨兵節點用
	listNode(T e, listNode<T> *p = nullptr, listNode<T> *s = nullptr) :data(e), pred(p), succ(s) {}
	//解構函式
	~listNode(){}

	//成員函式
	listNode<T>* insertAsPred(const T& e);  //在當前節點前插入一個新節點
	listNode<T>* insertAsSucc(const T& e);  //在當前節點後插入一個新節點
};

template<typename T> listNode<T>* listNode<T>::insertAsPred(const T& e)
{
	listNode<T> *p = new listNode<T>(e, pred, this);    //更新4個指標的指向
	pred->succ = p;
	pred = p;
	return p;
}

template<typename T> listNode<T>* listNode<T>::insertAsSucc(const T& e)
{
	listNode<T> *p = new listNode<T>(e, this, succ);
	succ->pred = p;
	succ = p;
	return p;
}

(2) list.h

#pragma once
#include "listNode.h"
typedef int Rank;

template<typename T> class list         //list結構:  [sentinel node]--[[first]...[]....[last]]--[sentinel node]
{
protected:                    
	int _size;    //list規模
	listNode<T> *header, *trailer;      //list的前後哨兵節點的指標

public:
	//建構函式
	list() { init(); }
	list(std::initializer_list<T> li);  //列表初始化構造方式
	list(listNode<T>* p, int n);        //拷貝構造,拷貝節點p及其後n個範圍內的所有節點
	list(list<T>& li) :list(li.header, li._size) {}    //拷貝構造,拷貝整個list物件
	list(list<T>& li, Rank lr, Rank rr);  //拷貝構造,拷貝指定list物件的指定區間
	//解構函式(只需要手動處理new的物件)
	~list();

	//普通成員函式
	void init();    //list初始化時建立前後哨兵節點,_size置0
	int size();     //返回list物件的規模
	void display(); //列印當前list中的所有元素
	listNode<T>* first();             //返回第一個有效節點的地址
	listNode<T>* last();              //返回最後一個有效節點的地址
	listNode<T>* find(const T& e, int n, listNode<T>* p); //在節點p之前的n個長度範圍內查詢元素e
	listNode<T>* find(const T& e);                        //查詢元素e
	listNode<T>* search(const T& e, int n, listNode<T>* p); //在節點p之前的n個長度範圍內查詢元素e(要求list為有序序列,返回不大於此元素的最大節點的指標)	
	listNode<T>* search(const T& e);         //查詢元素e(要求list為有序序列,返回不大於此元素的最大節點的指標)
	listNode<T>* insertAsFirst(const T& e);  //插入元素作為first節點
	listNode<T>* insertAsLast(const T& e);   //插入元素作為last節點
	listNode<T>* insertAsPred(listNode<T>* p, const T& e);  //在節點P之前插入元素e
	listNode<T>* insertAsSucc(listNode<T>* p, const T& e);  //在節點P之後插入元素e
	listNode<T>* insert(Rank r, const T& e);                //在指定秩出插入元素(警告:線性複雜度)
	T remove(listNode<T>* p);          //刪除指定節點
	int clear();		 //清除list內所有有效節點
	int deduplicate();   //去除list內重複元素
	int uniquify();      //去除list內重複元素(要求list為有序序列)
	void traverse(void(*func)(T &));		    //批量處理list內所有元素(函式指標方式)
	template<typename FuncClass> void traverse(FuncClass func);	//批量處理list內所有元素(函式物件方式)
	void sort(listNode<T>* p, int n,int s);           //排序介面彙總
	void insertionSort();        //插入排序法
	void insertionSort(listNode<T>* p,int n);   //對從p節點開始的n範圍內的節點進行排序
	void selectionSort();        //選擇排序法
	void selectionSort(listNode<T>* p, int n);  //對從p節點開始的n範圍內的節點進行排序
	void mergeSort(listNode<T>* p,int n);       //歸併排序法
	//過載運算子
	T& operator[](Rank r);  //下標運算子過載
	list<T>& operator=(const list<T>& li); //賦值運算子過載
};

template<typename T> void list<T>::init()
{
	header = new listNode<T>();     //建立前後哨兵節點
	trailer = new listNode<T>();
	_size = 0;
	header->succ = trailer;         //設定指標指向
	header->pred = nullptr;
	trailer->pred = header;
	trailer->succ = nullptr;
}

template<typename T> list<T>::list(std::initializer_list<T> li)
{
	init();   
	listNode<T> *p=header;
	for (auto iter = li.begin(); iter != li.end(); iter++)
	{
		p = p->insertAsSucc(*iter);
		_size++;
	}
}

template<typename T> list<T>::list(listNode<T>* p, int n)
{
	init();
	listNode<T> *ptr=header;
	while (n--)
	{	
		ptr=ptr->insertAsSucc(p->data);
		p = p->succ;
		_size++;
	}

}

template<typename T> list<T>::list(list<T>& li, Rank lr, Rank rr)
{
	init();
	listNode<T>* p = li.first();
	listNode<T>* ptr = header;
	for (int i = 0; i < rr; i++)
	{
		if (i < lr)
			p = p->succ;
		else
		{
			ptr = ptr->insertAsSucc(p->data);
			p = p->succ;
			_size++;
		}
	}
}

template<typename T> list<T>::~list()
{
	clear();   //清除所有有效節點
	delete header;
	delete trailer;
}

template<typename T> void list<T>::display()
{
	listNode<T>* p = header;
	cout << "size:" << _size << endl;
	if (_size)
	{
		for (Rank r = 0; r < _size; r++)
		{
			p = p->succ;
			(r < (_size - 1)) ? cout << p->data << "," : cout << p->data;
		}
		cout << endl;
	}
}

template<typename T> int list<T>::size()
{
	return _size;
}

template<typename T> listNode<T>* list<T>::find(const T& e, int n, listNode<T>* p)    //包含p節點,n>1才能搜尋
{
	while ((n--)&&(p!=header))  //已經遍歷n次或則到達header
	{
		if (p->data == e)
			return p;
		else
			p = p->pred;
	}
	return nullptr;
}

template<typename T> listNode<T>* list<T>::find(const T& e) 
{
	return find(e, _size - 1, last());
}

template<typename T> listNode<T>* list<T>::search(const T& e, int n, listNode<T>* p)   //包含p節點,n>1才能搜尋
{
	while ((n--) && (p != header))
	{
		if (p->data <= e) //返回不大於指定元素的最大節點,方便在其後面插入
			return p;
		else
			p = p->pred;	
	}
	return p;
}


template<typename T> listNode<T>* list<T>::search(const T& e)
{
	return search(e, _size + 1, last());
}

template<typename T> listNode<T>* list<T>::first()
{
	return header->succ;
}

template<typename T> listNode<T>* list<T>::last()
{
	return trailer->pred;
}

template<typename T> T& list<T>::operator[](Rank r)
{
	listNode<T>* p=header->succ;
	while (r-->0)   
	{
		p = p->succ;
	}
	return p->data;
}

template<typename T> listNode<T>* list<T>::insertAsFirst(const T& e)
{
	_size++;
	listNode<T> *p = header->insertAsSucc(e);   //函式內部已經更新了4個指標指向
	return p;
}

template<typename T> listNode<T>* list<T>::insertAsLast(const T& e)
{
	_size++;
	listNode<T> *p = trailer->insertAsPred(e);
	return p;
}

template<typename T> listNode<T>* list<T>::insertAsPred(listNode<T>* p, const T& e)
{
	_size++;
	return p->insertAsPred(e);
}

template<typename T> listNode<T>* list<T>::insertAsSucc(listNode<T>* p, const T& e)
{
	_size++;
	return p->insertAsSucc(e);
}

template<typename T> listNode<T>* list<T>::insert(Rank r, const T& e)
{
	listNode<T> *p=header;
	while (r--)
	{
		p = p->succ;
	}
	return insertAsSucc(p, e);
}

template<typename T> T list<T>::remove(listNode<T>* p)
{	
	T e = p->data;
	p->pred->succ = p->succ;
	p->succ->pred = p->pred;
	_size--;
	delete p;
	return e;
}

template<typename T> int list<T>::clear()
{
	int oldSize = _size;
	while (header->succ != trailer)
		remove(header->succ);
	return oldSize;
}

template<typename T> int list<T>::deduplicate()
{
	if (!_size) return 0;
	int n = 0;
	listNode<T>* p = header->succ;
	listNode<T>* lp;  //快取p的前一個元素
	for (int i = 0; i < _size;)
	{
		lp = p->pred;
		if (find(p->data, _size, p->pred))   //在當前元素之前尋找,越界則退出
		{
			remove(p);n++;
			p = lp->succ;
		}
		else
		{
			i++; 
			p = p->succ;
		}
	}
	return n;
}

template<typename T> int list<T>::uniquify()
{
	if (!_size) return 0;
	int oldSize = _size;
	listNode<T> *p = header->succ;
	while (p->succ!=trailer)   //隊尾越界停止
	{
		if (p->data == p->succ->data)
			remove(p->succ);
		else
			p = p->succ;		
	}
	return oldSize - _size;
}


template<typename T> void list<T>::traverse(void(*func)(T &))
{
	for (Rank r = 0; r < _size; r++)
		func((*this)[r]);
}

template<typename T> template<typename FuncClass> void list<T>::traverse(FuncClass func)
{
	for (Rank r = 0; r < _size; r++)
		func((*this)[r]);
}

template<typename T> list<T>& list<T>::operator=(const list<T> &li)
{
	clear();  //清空有效節點
	if (!li._size) return *this;
	listNode<T>* p = li.header;
	listNode<T>* lp = header;

	while ((p = p->succ) != li.trailer)
	{
		lp->insertAsSucc(p->data);
		lp = lp->succ;
		_size++;
	}
	return *this;
}

template<typename T> void list<T>::sort(listNode<T>* p, int n, int s)
{
	switch (s)
	{
	case 0:
		insertionSort(p, n); break;
	case 1:
		selectionSort(p, n); break;
	case 2:
		mergeSort(p, n); break;
	default:
		break;
	}
}

template<typename T> void list<T>::insertionSort()
{
	if (_size < 2) return;
	listNode<T> *p = header->succ;
	while (p != trailer)   //列尾溢位則終止
	{
		search(p->data, _size+1, p->pred)->insertAsSucc(p->data);
		_size++;
		p = p->succ;
		remove(p->pred);
	}
}

template<typename T> void list<T>::insertionSort(listNode<T>* p, int n)
{
	if (n < 2) return;
	int s = 0;
	while ((n--) && (p != trailer))   //變數n次或列尾溢位則終止
	{
		search(p->data, s, p->pred)->insertAsSucc(p->data);
		_size++;
		p = p->succ;
		remove(p->pred);
		s++;
	}
}

template<typename T> void list<T>::selectionSort()
{
	if (_size < 2) return;
	listNode<T> *p = first();
	listNode<T> *ptr;   //快取待刪除的節點指標
	for (int i = 0; i < _size; i++)   //_size次迭代
	{
		T min = first()->data;
		p = first();
		ptr = p;
		for (int j = 0; j < _size - i; j++)   //內迴圈找最小值並插入到last位置(保證排序穩定)
		{
			if ((p->data) <= min)
			{
				min = p->data;
				ptr = p;
			}
			p = p->succ;
		}
		remove(ptr);
		insertAsLast(min);
	}
}

template<typename T> void list<T>::selectionSort(listNode<T>* p, int n)
{
	if (n < 2) return;
	p = p->pred;
	listNode<T> *pp = p->succ;  //迭代指標
	listNode<T> *ptr;			//快取待刪除的節點指標
	listNode<T> *trail = p;		//排序區間的最後一個元素,即排序區間為(p->pred,trail)
	for (int i = 0; i < n+1; i++)
		trail = trail->succ;
	for (int i = 0; i < n; i++)			  //n次迭代
	{
		T min = (p->succ)->data;
		pp = p->succ;
		ptr = p->succ;
		for (int j = 0; j < n - i; j++)   //內迴圈找最小值並插入到trail位置(保證排序穩定)
		{
			if ((pp->data) <= min)
			{
				min = pp->data;
				ptr = pp;
			}
			pp = pp->succ;
		}
		remove(ptr);
		trail->insertAsPred(min);
		_size++;
	}
}

template<typename T> void list<T>::mergeSort(listNode<T>* p, int n)    //[p,p_n)
{
	if (n < 2) return;
	//開始分裂
	listNode<T>* ppred = p->pred;  //快取待排序list的前哨兵
	listNode<T>* pmi = p;  //計算中間節點
	for (int i = 0; i < (n >> 1); i++)       //[p0,p1,p2] n=3 ==>  [p0] [p1,p2]
	{
		pmi = pmi->succ;
	}
	mergeSort(p, n >> 1);         //這兩句遞迴語句表示已分離的兩個子序列均已經排序完成
	mergeSort(pmi, n - (n >> 1));

	//開始歸併(兩個有序短序列==》一個有序長序列)  [pred][AAAAAAAAA][BBBBBBBBB]

	//更新各端點的地址(在遞迴時插入和刪除改變了邏輯順序節點的實際實體地址)
	p = ppred->succ;
	pmi = p;  //計算中間節點
	for (int i = 0; i < (n >> 1); i++)      
	{
		pmi = pmi->succ;
	}
	for (Rank i = (n >> 1), j = (n - (n >> 1)); i || j;)
	{
		if ((i > 0) && (j == 0))   //只剩下前段list
		{	
			i--;
			ppred->insertAsSucc(p->data);
			ppred = ppred->succ;
			_size++;
			p = p->succ;
			remove(p->pred);
		}
		if ((j > 0) && (i == 0))    //只剩下後段list
		{
			j--;
			ppred->insertAsSucc(pmi->data);
			ppred = ppred->succ;
			_size++;
			pmi = pmi->succ;
			remove(pmi->pred);
		}
		if ((i > 0) && (j > 0))     //兩段list都有值,則選擇最小的插在前面
		{
			if ((p->data) < (pmi->data))
			{
				i--;
				ppred->insertAsSucc(p->data);
				ppred = ppred->succ;
				_size++;
				p = p->succ;
				remove(p->pred);
			}
			else
			{
				j--;
				ppred->insertAsSucc(pmi->data);
				ppred = ppred->succ;
				_size++;
				pmi = pmi->succ;
				remove(pmi->pred);
			}
		}
	}
}