資料結構與演算法——線性錶鏈式儲存(單迴圈連結串列)
阿新 • • 發佈:2019-01-11
今天總結迴圈單鏈表
什麼是單迴圈連結串列?
單鏈表終端結點的指標域是指向空的,如果將其指向頭結點,這樣就形成了一個環,那麼這種首尾相接的環就夠成了單迴圈連結串列.
單鏈表中我們都是用頭指標來表示的,但是在單迴圈連結串列裡,用尾指標(指向最後一個節點)。為什麼要這樣,因為如果用頭指標,那麼當查詢最後一個元素的時候,就要迴圈遍歷,時間複雜度為O(n),如果用尾指標,時間複雜度為O(1),而因為是迴圈的,所以頭指標很容易表示出來即rear->next,時間複雜度也是O(1)
單迴圈連結串列中需要注意兩點:
- 頭指標使用rear->next表示的
- 判斷某結點是否為尾結點條件是:rear->next==rear 而不是單鏈表中的
圖示(百度圖片擷取):
心得:在寫連結串列這塊的時候,由於指標有時會被繞,但我發現,一定要記住指標存放的就是地址,而這個地址通常表示的是一個結點。比如rear->next 代表的是頭指標,而頭指標裡存放的地址是頭結點的,也就是指向頭結點,其實就代表了是頭結點。指標這塊需要好好的理解,揣摩,我是認為寧可慢一點,想明白了,也比快了,糊里糊塗的效果更好。
具體程式碼實現:
結果:<span style="font-family:Courier New;font-size:14px;">#include <iostream> using namespace std; template <class T> struct Node{ T data; struct Node<T> *next; //指標域 }; template <class T> class CLinkList { public: //初始化空的迴圈單鏈表 CLinkList() { rear = new Node<T>; rear->next = rear; } CLinkList(T a[],int n); //初始化一個連結串列 ~CLinkList(); //解構函式 int GetLength(); //獲取單鏈表的長度 T Get(int i); //獲取線性表第i個位置上的元素 int Locate(T x); //查詢線性表中值為x的元素 返回其位置 void Insert(int i,T x); //將元素x插入到位置i上 T Delete(int i); //刪除位置i上的元素 並將刪除元素返回 void PrintLinkList(); //迴圈遍歷迴圈單鏈表中的各個元素 private: Node<T> *rear; //尾指標 }; /** 尾插法 用陣列元素初始化迴圈單鏈表 思路: 1.新建一頭結點,尾指標指向此頭結點 2.將頭結點地址賦值給頭結點指標域 即構成了一個空的單迴圈連結串列 3.for迴圈 開始插入節點。 3.1新建一個結點,將陣列元素賦值給結點的資料域 3.2使新建結點的指標域指向頭結點的指標域 形成迴圈 3.3將當前結點指向新建結點 3.4尾指標向後移一位 */ template <class T> CLinkList<T>::CLinkList(T a[],int n) { rear = new Node<T>; rear->next = rear; //採用尾插法 for(int i=0;i<n;i++) { Node<T> *s= new Node<T>; s->data = a[i]; s->next = rear->next ; rear->next = s; rear = rear->next; //尾指標向後移 } } template <class T> int CLinkList<T>::GetLength() { int count = 0; //計數器 Node<T> *p = rear->next; while(p!=rear) { count++; p = p->next; } return count; } /** 解構函式 用來釋放結點 */ template <class T> CLinkList<T>::~CLinkList() { Node<T> *p = rear->next; //初始化工作指標 Node<T> *q; //臨時結點 while(p!=rear) { q = p; p = p->next; delete q; } } template <class T> T CLinkList<T>::Get(int i) { if(i>GetLength()||i<1) return -1; //判斷查詢的位置是否是合理的 Node<T> *p = rear->next; for(int j=0;j<i;j++) { p = p->next; //得到位置i的節點 } return p->data; } template <class T> int CLinkList<T>::Locate(T x) { Node<T> *p = rear->next; int j=0; while(p!=rear) { if(p->data==x) return j; j++; p = p->next; } return -1; } template<class T> void CLinkList<T>::Insert(int i,T x) { Node<T> *p = rear->next; //獲取前一個結點 for(int j=0;j<i-1;j++) { p = p->next; } Node<T> *s = new Node<T>; s->data = x; s->next = p->next; p->next = s; } template <class T> void CLinkList<T>::PrintLinkList() { Node<T> *p = rear->next; //這裡是頭結點 for(int i=0;i<GetLength();i++) { cout<<p->next->data<<" "; //下一個節點的資料域 p = p->next; } cout<<endl; } template<class T> T CLinkList<T>::Delete(int i) { Node<T> *p = rear->next; for(int j=0;j<i-1;j++) { p = p->next; } Node<T> *q = p->next; //要刪除的結點 p->next = q->next; T x = q->data; delete q; return x; } int main() { int a[6] = {2,4,6,1,7,9}; CLinkList<int> list(a,6); cout<<"遍歷單鏈表的元素"<<endl; list.PrintLinkList(); cout<<"迴圈單鏈表的長度:"<<endl; cout<<list.GetLength()<<endl; cout<<"獲取位置2的元素:"<<endl; cout<<list.Get(2)<<endl; cout<<"獲取元素6所在的位置"<<endl; cout<<list.Locate(2)<<endl; cout<<"插入元素8到位置3"<<endl; list.Insert(3,8); list.PrintLinkList(); cout<<"栓出位置4上的元素"<<endl; list.Delete(4); list.PrintLinkList(); return 0; } </span>