數據結構複習 線性表的鏈接存儲結構及其實現

在此之前,我整理了用順序表存儲線性表的方法,但是順序表具有以下缺點:


  • 列表內容插入和刪除非常費勁。需要移動大量元素。
  • 表的容量難以確定。因爲順序表中數組的長度需要事先確定,所以難以確定合適的規模。
  • 造成存儲空間的“碎片”。數組要求連續的存儲空間,若不連續則不能使用,造成存儲空間的“碎片”現象。

這一次,我們嘗試用單鏈表存儲線性表。
有空的話,可以嘗試用循環鏈表和雙鏈表來改善,是個很高級的東西。

一、 單鏈表的存儲方法

通過每個指針的指針域連接線性表的數據元素。

二、單鏈表的實現

利用結構體類型來描述單鏈表的結點

template<class T>
struct Node
{
    T data;                     //指針域
    Node<T> * next;             //數據域
};

將線性表的抽象數據類型定義在單鏈表存儲結構下用C++中的class實現。

template<class T>
class LinkList
{
public:
    LinkList();
    LinkList(T a[], int n);
    ~LinkList();
    int Length();              //求單鏈表的長度
    T Get(int i);              //按位查找,查找第i個結點的元素值
    int Locate(T x);           //按值查找,查找元素值爲x的結點的位置
    void Insert(int i, T x);   //在第i個位置插入元素值爲x的結點
    T Delete(int i);           //刪除第i個結點
    void PrintList();          //遍歷
private:
    Node<T> * first;           //單鏈表的頭指針
};

1.構造函數

①無參構造函數

template<class T>
LinkList<T>::LinkList()
{
    first = new Node<T>;
    first->next = NULL;
}

②有參構造函數

template<class T>
LinkList<T>::LinkList(T a[], int n)
{
    first = new Node<T>;
    first->next = NULL;

    /*
        1.頭插法建立單鏈表
    for(int i = 0; i < n; i++)
    {
        Node<T> * s = new Node<T>;
        s->data = a[i];
        s->next = first->next;  //將節點s插到頭節點之後
        first->next = s;
    }
    */

    //  2.尾插法建立單鏈表
    Node<T> * r = first;        //尾指針初始化
    for(int i = 0; i < n; i++)
    {
        Node<T> * s = new Node<T>;
        s->data = a[i];
        r->next = s;
        r = s;
    }
    r->next = NULL;
}

2.按位查找算法 Get

template<class T>
T LinkList<T>::Get(int i)
{
    //工作指針p和累加器count初始化
    Node<T> * p = first->next;
    int count = 1;

    while(p != NULL && count < i)
    {
        p = p->next;
        count++;
    }
    if(p == NULL)
        throw "位置異常";
    else
        return p->data;
}

3.按值查找算法 Locate

template<class T>
int LinkList<T>::Locate(T x)
{
    Node<T> * p = first->next;
    int count = 1;          //用來記錄光標的位置
    while(p != NULL)
    {
        if(p->data == x)
            return count;
        p = p->next;
    }
    return 0;               //退出循環表示查找失敗
}

4.插入算法

void LinkList<T>::Insert(int i, T x)    //在第i個位置插入元素x
{
    Node<T> * p = first;
    int count = 0;
    //找出第i-1個元素
    while(p != NULL && count < i - 1)
    {
        p = p->next;            //工作指針p向後移
        count++;
    }
    if(p == NULL)
        throw "位置異常";
    else
    {
        Node<T> * s = new Node<T>;
        s->data = x;
        s->next = p->next;
        p->next = s;
    }
}

5.刪除算法

template<class T>
T LinkList<T>::Delete(int i)
{
    Node<T> * p = first;
    int count = 0;
    while(p != NULL && count < i - 1)
    {
        p = p->next;
        count++;
    }
    if(p == NULL)
        throw "位置異常";
    else
    {
        //暫存被刪節點
        Node<T> * q = p->next;
        int x = q->data;

        p->next = q->next;
        delete q;
        return x;
    }
}

7.求鏈表的長度

int LinkList<T>::Length()
{
    //工作指針p和累加器count初始化
    Node<T> * p = first->next;
    int count = 0;

    while(p != NULL)
    {
        count++;
        p = p->next;
    }
    return count;
}

8.遍歷

void LinkList<T>::PrintList()
{
    Node<T> * p = first->next;
    while(p != NULL)
    {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}

9.析構函數算法

template<class T>
LinkList<T>::~LinkList()
{
    Node<T> *q = new Node<T>;
    while(first != NULL)        //釋放單鏈表的每個結點的存儲空間
    {
        q = first;              //暫存被釋放結點
        first = first->next;    //first指向被釋放結點的下一個結點
        delete q;
    }
}

完整代碼如下:

#include <iostream>
#define maxSize 100
using namespace std;

template<class T>
struct Node
{
    T data;                     //指針域
    Node<T> * next;             //數據域
};
template<class T>
class LinkList
{
public:
    LinkList();
    LinkList(T a[], int n);
    ~LinkList();
    int Length();              //求單鏈表的長度
    T Get(int i);              //按位查找,查找第i個結點的元素值
    int Locate(T x);           //按值查找,查找元素值爲x的結點的位置
    void Insert(int i, T x);   //在第i個位置插入元素值爲x的結點
    T Delete(int i);           //刪除第i個結點
    void PrintList();          //遍歷
private:
    Node<T> * first;           //單鏈表的頭指針
};
template<class T>
LinkList<T>::LinkList()
{
    first = new Node<T>;
    first->next = NULL;
}
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
    first = new Node<T>;
    first->next = NULL;

    /*
        1.頭插法建立單鏈表
    for(int i = 0; i < n; i++)
    {
        Node<T> * s = new Node<T>;
        s->data = a[i];
        s->next = first->next;  //將節點s插到頭節點之後
        first->next = s;
    }
    */

    //  2.尾插法建立單鏈表
    Node<T> * r = first;        //尾指針初始化
    for(int i = 0; i < n; i++)
    {
        Node<T> * s = new Node<T>;
        s->data = a[i];
        r->next = s;
        r = s;
    }
    r->next = NULL;
}
template<class T>
void LinkList<T>::PrintList()
{
    Node<T> * p = first->next;
    while(p != NULL)
    {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}
template<class T>
int LinkList<T>::Length()
{
    //工作指針p和累加器count初始化
    Node<T> * p = first->next;
    int count = 0;

    while(p != NULL)
    {
        count++;
        p = p->next;
    }
    return count;
}
template<class T>
T LinkList<T>::Get(int i)
{
    //工作指針p和累加器count初始化
    Node<T> * p = first->next;
    int count = 1;

    while(p != NULL && count < i)
    {
        p = p->next;
        count++;
    }
    if(p == NULL)
        throw "位置異常";
    else
        return p->data;
}
template<class T>
int LinkList<T>::Locate(T x)
{
    Node<T> * p = first->next;
    int count = 1;          //用來記錄光標的位置
    while(p != NULL)
    {
        if(p->data == x)
            return count;
        p = p->next;
    }
    return 0;               //退出循環表示查找失敗
}
template<class T>
void LinkList<T>::Insert(int i, T x)    //在第i個位置插入元素x
{
    Node<T> * p = first;
    int count = 0;
    //找出第i-1個元素
    while(p != NULL && count < i - 1)
    {
        p = p->next;            //工作指針p向後移
        count++;
    }
    if(p == NULL)
        throw "位置異常";
    else
    {
        Node<T> * s = new Node<T>;
        s->data = x;
        s->next = p->next;
        p->next = s;
    }
}
template<class T>
T LinkList<T>::Delete(int i)
{
    Node<T> * p = first;
    int count = 0;
    while(p != NULL && count < i - 1)
    {
        p = p->next;
        count++;
    }
    if(p == NULL)
        throw "位置異常";
    else
    {
        //暫存被刪節點
        Node<T> * q = p->next;
        int x = q->data;

        p->next = q->next;
        delete q;
        return x;
    }
}
template<class T>
LinkList<T>::~LinkList()
{
    Node<T> *q = new Node<T>;
    while(first != NULL)        //釋放單鏈表的每個結點的存儲空間
    {
        q = first;              //暫存被釋放結點
        first = first->next;    //first指向被釋放結點的下一個結點
        delete q;
    }
}
int main()
{
    int a[maxSize], i, SearchPos, NewPos, NewItem, DelPos ;
    int n = 0;

    //創建順序表
    cout << "請輸入順序表長度:" ;
    cin >> n ;    //輸入樣本數目(表長)
    cout << "請輸入表中所有元素:";
    for (i = 0 ; i < n; i++)
    {
        cin >> a[i] ;
    }
    LinkList<int> linkList(a, n);

    cout << "該順序表爲:";
    linkList.PrintList();   //顯示順序表
    cout << "請輸入所查找的元素的位置:" ;
    cin >> SearchPos ;    //輸入查找位置
    cout << "該位置的元素爲:" << linkList.Get(SearchPos) << endl ;   //輸出查找的數據元素值

    cout << "請輸入所插入元素的值:" ;
    cin >> NewItem ;        //插入位置輸入
    cout << "請輸入所插入的元素的位置:" ;
    cin >> NewPos ;    //插入元素輸入
    linkList.Insert(NewPos, NewItem) ;     //新數據插入順序表中

    cout << "插入後的順序表爲:" ;
    linkList.PrintList();        //插入數據後,輸出新的順序表

    cout << "請輸入所刪除元素的位置:" ;
    cin >> DelPos ;        //輸入刪除元素位置
    linkList.Delete(DelPos) ;    //按位置刪除數據

    cout << "刪除後的順序表爲:" ;
    linkList.PrintList();
    return 0 ;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章