zoukankan      html  css  js  c++  java
  • 链表

    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

    ------------ 转载请注明出处 ------------
  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/whlook/p/6551474.html
Copyright © 2011-2022 走看看