線性表學習總結(順序表和鏈表)

線性表主要分爲兩種,順序表和鏈表。
順序表主要利用的是數組,大部分時候只需要重新定義數組的插入或刪除操作就可以,所以順序表的存儲結構跟數組是相同的,都是一串連在一起的內存。因此,順序表在存儲數據的同時也保存了數據之間的邏輯關係。並且可以通過訪問數組下標直接訪問對應元素。這裏主要總結鏈表。
鏈表是將內存中零散的不連續的部分連接在一起,這個起連接作用的東西就是指針。我們可以用過指針去訪問已知的可以訪問的地址,這就好比偵探遊戲,如果沒有明確的線索,再聰明的偵探也沒辦法接近真相,而對於鏈表的設計者而言,指針就是線索,失去了指針,鏈表也就沒辦法延續下去。
爲了同時存儲數據和邏輯關係,需要把這兩部分整合到一起,Node結構體應運而生。

template<typename T>
struct Node
{
	T data;
	Node<T>*next;
};

在這裏我們用到了模板,這麼做可以讓代碼的服用程度更高,不做過多解釋。
在Node的定義中不難看出,Node本身包含一個指向自身類型的指針,具體的可以說指針next指向下一個節點Node。
圖爲節點結構示意圖在使用鏈表前,應該先創建鏈表。
創建鏈表分爲兩種,帶頭結點與不帶頭節點的創建,而這唯一的區別就是,頭指針First指向的Node型內存中是否有具體的數據。如果有就是不帶頭結點的創建方式,此時鏈表是有一個元素的,反之就是帶頭結點的創建方式。但是它們的next均指向NULL(也就是空懸),至此我們完成了空鏈表的創建。稍加思考不難發現,帶頭結點的創建方式可以將空表與非空表的創建統一起來,更加方便(這不絕對,視情況而定)。
具體代碼實現如下:

template <typename T>
class LinkList
{
    private:
    Node<T>* first;
    public:
    LinkList();//
    LinkList(T a[],int n);//
    LinkList(T a[],int n,int tail);//
    ~LinkList();//
    int Length();//
    T LocationFind(int i);//
    int ValueFind(T value);//
    void Insert(int i,T x);
    T LocationDelete(int n);//
    int ValueDelete(T x);//
    bool Empty();
    void Print();
};
template <typename T>
LinkList<T>::LinkList()
{
    first = new Node<T>;
    first->next = NULL;
}

first指針是指向第一個節點的必備指針,如果沒有first,鏈表就無跡可尋,簡單地講,我們把鏈表弄丟了。
創建完空表後我們就可以進行插入了,當然也可以寫一個非空表的創建,不過這些操作都可以用插入代替。不同於順序表,鏈表需要依次處理每個節點,這是其分佈結構決定的,也是區別於順序表最大的不同。我們可以選擇按值插入或者按地址插入,不過這都需要先找到符合條件的指針,因此設置工作指針p,p從頭節點開始遍歷鏈表,通過p = p->next 進行後移,直到鏈表結束或者找到符合條件的節點。
具體代碼實現如下:

cpp
template<typename T>
void LinkList<T>::Insert(int n,T x)
{
    Node<T>* p = first;
    int counts = 0;
    while(p->next!=NULL&&counts<n-1)
    {
        p = p->next;
        counts++;
    }
    if(p->next==NULL) throw "插入位置錯誤";
    else{
        Node<T>* q = new Node<T>;
        q->data = x;
        q->next = p->next;
        p->next = q;
    }
}


查找操作其實就是插入操作的一部分,同樣可以分爲按值查找和按地址查找。
具體代碼實現如下:

template <typename T>
T LinkList<T>::LocationFind(int i)
{
    Node<T>* p = first->next;
    int counts = 0;
    while(p!=NULL&&counts<i-1)
    {
        p = p->next;
        counts++;
    }
    if(p==NULL) return -1;
    else return p->data;
}
template <typename T>
int LinkList<T>::ValueFind(T x)
{
    Node<T>* p = first->next;
    int counts = 1;
    while(p!=NULL)
    {
        if(p->data==x) return counts;
        else{
                p = p->next;
                counts++;
        }
    }
    return -1;
}

刪除操作是在查找操作的前提下進行的,只需要地址刪除就足夠了,因爲按值查找返回的就是地址,可以調用其獲取。
具體代碼實現如下:

template <typename T>
T  LinkList<T>::Delete(int n)
{
    T x;
    Node<T> *p = first, *q = NULL; //工作指針p指向頭結點
    int count = 0;
    while (p != NULL && count < n - 1) //查找第i-1個結點
    {
        p = p->next;
        count++;
    }
    if (p == NULL || p->next == NULL || n == 0) //結點p不存在或p的後繼結點不存在
    return -1;
    //throw "Error";
    else {
            q = p->next; x = q->data; //暫存被刪結點
            p->next = q->next; //摘鏈
            delete q;
            return x;
        }
}

定義完增刪查改後,其他操作都可以在此基礎上進行。
最後是鏈表的析構,設置工作指針,依次後移,直至鏈表爲空,並回收內存。
具體代碼實現如下:

template <typename T>
LinkList<T>::~LinkList()
{
    Node<T>* p = first;
    while(first->next!=NULL)
    {
        first = first->next;
        delete p;
        p = first;
    }
}

回收內存十分重要,不可省略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章