鏈表


1.基本概念

  鏈表 (Linked List)是一種線性表,但是在內存中不是按照線性的順序儲存數據,是通過每個節點的指針指向下一個節點的指針來鏈接。相對於順序儲存(例如數組),鏈表的插入操作更快( O(1) ),但是失去了隨機讀取的優點。

  鏈表一般有單向鏈表,雙向鏈表,循環鏈表這三種形式。

2.單向鏈表

  該種形式是鏈表中最簡單的,每個節點包含了數據域指針域,數據域用來保存該節點的值,指針域用來指向下一個節點(鏈表的尾巴節點應指向NULL),它保存的是下一個節點的地址。

  一般完整的鏈表會有頭節點,頭節點不儲存數據。查找數據的話要從頭節點開始,每次訪問下一個節點直到查找到數據或到達尾部。

  單向鏈表典型的插入方法有頭插法尾插法,頭插法只需要一個頭指針,而尾插法還需要一個指向尾部的尾指針。

 

單向鏈表的C++實現:

template<class T>
struct Node // 節點的數據結構
{
    T data;
    Node *next;

    Node() :next(nullptr){}  // 無參構造
    Node(T t) :data(t), next(nullptr){} // 帶參數構造
};

template<class T>
class LinkList  //鏈表類
{
private:
    Node<T> *head; // 頭指針 (空節點)
    Node<T> *tail; // 尾指針 (空節點)
    int size;
public:
    LinkList()
    {
        head = new Node<T>;
        tail = new Node<T>;

        size = 0;
    }
    ~LinkList()
    {

    }
public:
   /**
    *    在鏈表的頭部插入新節點
    *        @param val:賦給新節點的值
    */
    void insertOnHead(T val);

   /**
    *    在鏈表的尾部插入新節點
    *        @param val:賦給新節點的值
    */
    void insertOnTail(T val); 

   /**
    *    在鏈表的某一位置插入新節點,插入成功返回true,否則返回false
    *        @param i:指定的位置
    *        @param val:賦給新節點的值
    */
    bool insert(int i,T val); 

   /**
    *    獲取某節點的值,獲取成功返回true,否則返回false
    *        @param i:指定的位置
    *        @param val:賦給新節點的值    
    */
    bool getData(int i,T &val); 

   /**
    *    判斷空,空的話返回true,否則返回false
    */
    bool isEmpty(); 

   /**
    *    清空鏈表
    */
    void clear(); 

   /**
    *    打印鏈表
    */
    void printList();
};

template<class T>
void LinkList<T>::insertOnHead(T val)
{
    Node<T> *newNode = new Node<T>;
    newNode->data = val;
    newNode->next = head->next;
    head->next = newNode;

    if (!size)
        tail->next = newNode; // 把尾指針指向第一個節點
    ++size;
}
template<class T>
void LinkList<T>::insertOnTail(T val)
{
    Node<T> *newNode = new Node<T>;
    newNode->data = val;
    newNode->next = nullptr;
    tail->next->next = newNode;
    tail->next = newNode;
    ++size;
}
template<class T>
bool LinkList<T>::insert(int i,T val)
{
    if (i <= 0|| i > size)
        return false;

    Node<T> *newNode = new Node<T>;
    Node<T> *temp = head;

    if (i == size)
        tail->next = newNode; // 如果在最后插入,更新尾指針

    for (int j = 0; j <= size; ++j)
    {
        if (i != 0)
        {
            temp = temp->next;
            --i;
        }
        else
        {
            newNode->data = val;
            newNode->next = temp->next;
            temp->next = newNode;
            break;
        }
            
    }

    ++size;
    return true;
    
    
}

template<class T>
bool LinkList<T>::getData(int i, T &val)
{
    if (i <= size && i > 0)
    {
        Node<T> *temp = head;
        for (int j = 0; j < i; ++j)
        {
            temp = temp->next;
        }
        val = temp->data;
        return true;
    }
    else
    {
        return false;
    }
}
template<class T>
bool LinkList<T>::isEmpty()
{
    return size ? false : true;
}
template<class T>
void LinkList<T>::clear()
{
    Node<T> *tempFront = head->next;  // 指向下一個待刪除
    Node<T> *tempBack = head->next;   // 指向待刪除的元素
    for (int i = 0; i < size; ++i)
    {
        tempBack = tempFront;
        tempFront = tempFront->next;
        delete tempBack;
    }
    size = 0;
}
template<class T>
void LinkList<T>::printList()
{
    if (!size)
    {
        cout << "empty link" << endl;
        return;
    }

    Node<T> * temp = head->next;
    for (int i = 0; i < size; ++i)
    {
        cout << temp->data << endl;
        temp = temp->next;
    }
}
View Code

 

2.雙向鏈表

  和單向鏈表類似,不過雙向鏈表的每個節點包含一個數據域兩個指針域,一個前向指針和一個后向指針,相對單鏈表的優點是可以訪問前驅而不用從頭節點開始,其結構如下圖:

  其實鏈表的操作是相似的,都是對節點的連接和斷開與銷毀,不過雙向鏈表需要注意的是增加了對前向指針的操作,新增節點的圖示如下:

  雙向鏈表插入的C++示例如下,完整代碼見GitHub。

 

bool insert(int i,T val)
{
    if (i <= 0|| i > size)
        return false;

    Node *newNode = new Node;
    Node *temp = head;

    if (i == size)
        tail->next = newNode; // 如果在最后插入,更新尾指針

    for (int j = 0; j <= size; ++j)
    {
        if (i != 0)
        {
            temp = temp->next;
            --i;
        }
        else
        {
            newNode->data = val;
            newNode->pre = temp;
            newNode->next = temp->next;
            temp->next = newNode;
            break;
        }
            
    }

    ++size;
    return true;
    
    
}

 

GitHub:https://github.com/whlook/LinkList


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM