1. 程式人生 > >資料結構與演算法——線性錶鏈式儲存(單迴圈連結串列)

資料結構與演算法——線性錶鏈式儲存(單迴圈連結串列)

今天總結迴圈單鏈表

什麼是單迴圈連結串列?

單鏈表終端結點的指標域是指向空的,如果將其指向頭結點,這樣就形成了一個環,那麼這種首尾相接的環就夠成了單迴圈連結串列.

單鏈表中我們都是用頭指標來表示的,但是在單迴圈連結串列裡,用尾指標(指向最後一個節點)。為什麼要這樣,因為如果用頭指標,那麼當查詢最後一個元素的時候,就要迴圈遍歷,時間複雜度為O(n),如果用尾指標,時間複雜度為O(1),而因為是迴圈的,所以頭指標很容易表示出來即rear->next,時間複雜度也是O(1)

單迴圈連結串列中需要注意兩點:

  • 頭指標使用rear->next表示的
  • 判斷某結點是否為尾結點條件是:rear->next==rear 而不是單鏈表中的
    p->next==NULL

圖示(百度圖片擷取):

心得:在寫連結串列這塊的時候,由於指標有時會被繞,但我發現,一定要記住指標存放的就是地址,而這個地址通常表示的是一個結點。比如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>
結果: