二、C++實現list資料結構
阿新 • • 發佈:2018-12-08
本文使用c++實現list資料結構,list的介面函式採用高效的實現方式,這樣一方面使我加深對資料結構的理解,另一方便可以讓我再複習複習c++,通過前幾天寫的vector資料結構的底層實現,我確實又進一步地熟悉使用C++進行程式設計,,這次寫list的實現過程中,我幾乎沒有怎麼檢視《c++prime》了哈哈,就是函式物件形式的遍歷函式的宣告格式怎麼也想不起來,後來查書才明白函式的形參其實是個類的物件,只不過這個類名要在宣告前指明,如下:
template<typename FuncClass> void traverse(FuncClass func);
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(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);
}
}
}
}