• 数据结构-单向链表 C和C++的实现


    数据结构,一堆数据的存放方式。

    今天我们学习数据结构中的 链表

    链表的结构:

    链表是一种特殊的数组,它的每个元素称为节点,每个节点包括两个部分:

    • 数据域:存放数据,此部分与数组相同
    • 指针域:存放了下一个节点的地址(单向链表)、存放上一个和下一个节点的地址(双向链表)

    链表比数组多了指针域,因为链表结构是通过上一个节点的指针域去找下一个数据,比如有一个链表ABCD四个节点,其中A节点是链表的第一个节点,如果我们要访问D节点里边的数据。操作如下:

    1. 先通过A节点的指针域找到B节点
    2. 再通过B节点的指针域找到C节点
    3. 再通过C节点的指针域找到D节点
    4. 获取D节点数据域的数据

    对比数组直接通过下标访问如x=Array[3],链表的访问方式相当麻烦,既然这么麻烦,为什么还有链表这种数据结构呢?因为链表插入删除节点方式十分便捷,在数据量大的时候,删除数组的数据需要把删除数据后面的数据都前移一位,而链表只需要改变前一个元素的指针域,插入和删除操作速度快

    这么厉害的东西,还是看程序比较直接

    单向链表

    1、C语言

    1.1、程序清单

    本程序包含3个文件

    它们分别是:

    (此处插入图)

    linkList.h:

    #ifndef _LINKLIST_H
    #define _LINKLIST_H
    
    typedef int Elem;
    typedef unsigned char uint8_t;
    struct LkNode 
    {
        Elem m_eData;
        struct LkNode *m_iNext;
    };
    struct LinkList
    {
        struct LkNode *m_stListHead;
        int m_iLength;
        int m_iSize;
    };
    
    uint8_t LinkListCreate(struct LinkList *list,int size);
    uint8_t LinkListDeleteAll(struct LinkList *list);
    uint8_t IsLinkListEmpty(struct LinkList *list);
    uint8_t IsLinkListFull(struct LinkList *list);
    int GetLinkListLength(struct LinkList *list);
    int GetLinkListElemIndex(struct LinkList *list,Elem elem);
    uint8_t GetListElem(struct LinkList *list,int index,Elem *elem);
    //uint8_t GetLinkListPrevious(int index,Elem* elem); 
    //uint8_t GetLinkListNext(int index,Elem* elem);
    uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem);
    uint8_t LinkListInsertHead(struct LinkList *list,Elem elem);
    uint8_t LinkListInsertTail(struct LinkList *list,Elem elem);
    uint8_t LinkListDelete(struct LinkList *list,int index,Elem *getElem);
    void LinkListPrintAll(struct LinkList *list);
    
    
    #endif
    View Code

    LinkList.c

    #include "LinkList.h"
    #include <stdlib.h>
    #include <stdio.h>
    
    
    uint8_t LinkListCreate(struct LinkList *list,int size);
    uint8_t LinkListDeleteAll(struct LinkList *list);
    uint8_t IsLinkListEmpty(struct LinkList *list);
    uint8_t IsLinkListFull(struct LinkList *list);
    int GetLinkListLength(struct LinkList *list);
    int GetLinkListElemIndex(struct LinkList *list,Elem elem);
    uint8_t GetListElem(struct LinkList *list,int index,Elem *elem);
    //uint8_t GetLinkListPrevious(int index,Elem* elem); 
    //uint8_t GetLinkListNext(int index,Elem* elem);
    uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem);
    uint8_t LinkListInsertHead(struct LinkList *list,Elem elem);
    uint8_t LinkListInsertTail(struct LinkList *list,Elem elem);
    uint8_t LinkListDelete(struct LinkList *list,int index,Elem *getElem);
    void LinkListPrintAll(struct LinkList *list);
    
    
    uint8_t LinkListCreate( struct LinkList *list,int size)
    {
        if(size<=0)
        {
            return 0;
        }
    
        list->m_stListHead = (struct LkNode *)malloc(sizeof(struct LkNode)); 
        
        //List head haven't datas,and set list length = 0
        list->m_stListHead->m_eData=0;//head Node haven't data
        list->m_stListHead->m_iNext=NULL;
        list->m_iLength = 0;
        list->m_iSize = size;
        return 1;
    }
    
    uint8_t LinkListDeleteAll( struct LinkList *list)
    {
        struct LkNode *deleteNode ;
        struct LkNode *nextNode ;
        int i;
        if(IsLinkListEmpty(list))
        {
            return 0;
        }
    
        deleteNode = list->m_stListHead->m_iNext;
        nextNode = deleteNode->m_iNext;
    
    
        for(i=0;i<list->m_iLength ;i++)
        {
            nextNode = deleteNode->m_iNext;
            free(deleteNode);
            deleteNode = nextNode;
        }
        deleteNode = NULL;
        nextNode =NULL;
        list->m_iLength = 0;
        return 1;
    }
    
    
    uint8_t IsLinkListEmpty(struct LinkList *list)
    {
        if(list->m_iLength == 0)
        {
            return 1;
        }
        return 0;
    }
    uint8_t IsLinkListFull(struct LinkList *list)
    {
        if(list->m_iLength >=list->m_iSize)
        {
            return 1;
        }
        return 0;
    }
    
    int GetLinkListElemIndex(struct LinkList *list,Elem elem)
    {
        struct LkNode *tempNode = list->m_stListHead;
        int i;
        for(i=0;i<list->m_iLength ;i++)
        {
            tempNode = tempNode->m_iNext;
            if(tempNode->m_eData == elem)
            {
                return i;        
            }
        }
        return -1;
    }
    uint8_t GetListElem(struct LinkList *list,int index,Elem *elem)
    {    
        struct LkNode *tempNode;
        int i;
        if(index<0 ||index >=list->m_iLength )
        {
            return 0;
        }
    
        tempNode = list->m_stListHead;
        for(i=0;i<=index;i++)
        {
            tempNode = tempNode->m_iNext;
        }
        *elem = tempNode->m_eData;
        return 1;
    }
    uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem)
    {
        struct LkNode *preNode = list->m_stListHead;
        struct LkNode *newNode;
        struct LkNode *nextNode;
        int i;
        
        if(index<0 || index>list->m_iLength)
        {
            return 0;
        }
        if(IsLinkListFull(list))
        {
            return 0;
        }
    
        newNode = (struct LkNode *)malloc(sizeof(struct LkNode));
        if(newNode ==NULL)//heap empty
        {
            return 0;
        }
        for(i=0;i<index;i++)
        {
            preNode = preNode->m_iNext;
        }
        nextNode = preNode->m_iNext;
        preNode->m_iNext = newNode;
        newNode->m_eData = elem;
        newNode->m_iNext = nextNode;
    
        list->m_iLength++;
        return 1;
    }
    uint8_t LinkListInsertHead(struct LinkList *list,Elem elem)
    {
        return LinkListInsert(list,0,elem);
    }
    uint8_t LinkListInsertTail(struct LinkList *list,Elem elem)
    {
        return LinkListInsert(list,list->m_iLength ,elem);
    }
    
    uint8_t LinkListDelete(struct LinkList *list,int index,Elem *elem)
    {
        struct LkNode *preNode = list->m_stListHead;
        struct LkNode *nextNode;
        int i;
        if(index<0 || index >= list->m_iLength)
        {
            return 0;
        }
    
        for(i=0;i<index;i++)
        {
            preNode = preNode->m_iNext;
        }
        nextNode = preNode->m_iNext ->m_iNext;
        *elem = preNode->m_iNext->m_eData;//get delete data
        free(preNode->m_iNext);    //delete node of index
        preNode->m_iNext = nextNode;
    
        list->m_iLength--;
        return 1;
    }
    
    void LinkListPrintAll(struct LinkList *list)
    {
        struct LkNode *tempNode = list->m_stListHead;
        int i;
    
        printf("list:
    ");
        for(i=0;i<list->m_iLength;i++)
        {
            tempNode = tempNode->m_iNext;
            printf("%d
    ",*tempNode);
        }
        printf("end
    ");
    }
    LinkList.c

    最后在main.h中测试

    #include "LinkList.h"
    #include <stdlib.h>
    #include <stdio.h>
    
    
    int main(void)
    {
        int data[10]={0,1,2,3,4,5,6,7,8,9};
        int deletedata;
        int GetListElemData;
        int i;
    
        struct LinkList *list = (struct LinkList *)malloc(sizeof(struct LinkList ));
        LinkListCreate(list,10);
    
        //LinkListInsert check;
        printf("LinkListInsert: 1-5:
    ");
        for(i=0;i<5;i++)
        {
            if(LinkListInsert(list,i,data[i]))
                printf("Insert succeed:%d
    ",data[i]);
            else
                printf("Insert fail:%d
    ",data[i]);
        }
        LinkListPrintAll(list);
    
        //GetLinkListElemIndex check
        printf("GetLinkListElemIndex:data[3]:%d
    ",GetLinkListElemIndex(list,data[3]));
        
        //GetListElem check
        GetListElem(list,2,&GetListElemData);
        printf("GetListElem list second data:%d
    ",GetListElemData);
    
        //LinkListDelete check
        if(LinkListDelete(list,5,&deletedata))
            printf("LinkListDelete (getData:%d)
    ",deletedata );
        else
            printf("LinkListDelete fail
    ");
        LinkListPrintAll(list);
    
        //LinkListInsertHead and LinkListInsertTail
        printf("LinkListInsertHead:data[7] and LinkListInsertTail:data[8]
    ");
        LinkListInsertHead(list,data[7]);
        LinkListInsertTail(list,data[8]);
        LinkListPrintAll(list);
    
        //LinkListDeleteAll check
        printf("LinkListDeleteAll:
    ");
        LinkListDeleteAll(list);
        LinkListPrintAll(list);
        
        free(list);
        list=NULL;
    
        system("pause");
        return 0;
    }

    测试结果

    (此处补图)

    1.2详解:

    本部分讲解几个重要额函数,它们分别是:

    1、链表创建函数 uint8_t LinkListCreate( struct LinkList *list,int size)

      在这个函数中,首个参数*list是把链表结构体传入,设定链表的头节点(头节点只有指针域没有数据)、使用参数size来规定链表的最大容纳空间、并把链表现在长度置0。

      

    uint8_t LinkListCreate( struct LinkList *list,int size)
    {
        if(size<=0)
        {
            return 0;
        }
    
        list->m_stListHead = (struct LkNode *)malloc(sizeof(struct LkNode)); 
        
        //List head haven't datas,and set list length = 0
        list->m_stListHead->m_eData=0;//head Node haven't data
        list->m_stListHead->m_iNext=NULL;
        list->m_iLength = 0;
        list->m_iSize = size;
        return 1;
    }
    创建链表

    2、链表清空函数 uint8_t LinkListDeleteAll( struct LinkList *list)

      参数*list传入链表地址,通过list中的链表长度参数来删除链表,具体方法是:

    1.   创建一个deleteNode指针指向头节点的下一个元素(第0号元素);
    2.   创建nextNode指针指向deleteNode的下一号元素(第1号元素);
    3.   删除掉deleteNode的内容;
    4.   deleteNode指针指向nextNode的内容(第1号元素);
    5.   上边的234步骤循环直到所用内容删除;
    uint8_t LinkListDeleteAll( struct LinkList *list)
    {
        struct LkNode *deleteNode ;
        struct LkNode *nextNode ;
        int i;
        if(IsLinkListEmpty(list))
        {
            return 0;
        }
    
        deleteNode = list->m_stListHead->m_iNext;
        nextNode = deleteNode->m_iNext;
    
    
        for(i=0;i<list->m_iLength ;i++)
        {
            nextNode = deleteNode->m_iNext;
            free(deleteNode);
            deleteNode = nextNode;
        }
        deleteNode = NULL;
        nextNode =NULL;
        list->m_iLength = 0;
        return 1;
    }
    链表全部元素删除

    3、链表插入函数uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem)

      参数*list传入链表地址,index传入插入节点的位置(插入在第几号节点),elem传入节点的数据部分

    1.   判断一下传入的参数是否有,有问题则返回0插入失败
    2.   用malloc申请一个newNode(新的节点);
    3.   找到第index-1的节点(存放在preNode);
    4.   找到第index的节点(存放在nextNode);
    5.   把preNode的Next指针指向newNode;
    6.   把newNode的Next指针指向nextNode;(到这里已经完成插入节点,原来的index元素变成了index+1号元素)
    7.   增加list的长度m_iLength;
    uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem)
    {
        struct LkNode *preNode = list->m_stListHead;
        struct LkNode *newNode;
        struct LkNode *nextNode;
        int i;
        
        if(index<0 || index>list->m_iLength)
        {
            return 0;
        }
        if(IsLinkListFull(list))
        {
            return 0;
        }
    
        newNode = (struct LkNode *)malloc(sizeof(struct LkNode));
        if(newNode ==NULL)//heap empty
        {
            return 0;
        }
        for(i=0;i<index;i++)
        {
            preNode = preNode->m_iNext;
        }
        nextNode = preNode->m_iNext;
        preNode->m_iNext = newNode;
        newNode->m_eData = elem;
        newNode->m_iNext = nextNode;
    
        list->m_iLength++;
        return 1;
    }
    链表插入节点

    2、C++语言

    在C++中,使用模板的方法实现

    本程序包括3个文件组成,他们分别是:

    定义节点类:Node.h

    这个类定义了每个节点的两个区域:m_tpData数据域 和 m_tpNext指针域:

    #include <iostream>
    
    using namespace std;
    
    template <typename T>
    class Node
    {
    public:
        Node();
        Node(T data);
        ~Node();
        void setData(T data);
        T getData();
        void setNext(Node<T> *next);
        Node* getNext();
        void printData();
    private:
        T *m_tpData;
        Node<T> *m_tpNext;
    };
    
    
    template <typename T>
    Node<T>::Node()
    {
        m_tpData = new T;
        m_tpNext=NULL;
    }
    
    template <typename T>
    Node<T>::Node(T data)
    {
        m_tpData = new T(data);
        m_tpNext=NULL;
    }
    
    template <typename T>
    Node<T>::~Node()
    {
        delete m_tpData;
        m_tpData=NULL;
    }
    
    template <typename T>
    void Node<T>::setData(T data)
    {
        *m_tpData = data;
    }
    
    template <typename T>
    T Node<T>::getData()
    {
        return *m_tpData;
    }
    
    template <typename T>
    void Node<T>::setNext(Node<T> *next)
    {
        m_tpNext = next;
    }
    
    template <typename T>
    Node<T>* Node<T>::getNext()
    {
        return m_tpNext;
    }
    
    template <typename T>
    void Node<T>::printData()
    {
        cout<<*m_tpData<<endl;
    }
    View Code

    链表类 LinkList.h

    #include <iostream>
    #include "Node.h"
    
    using namespace std;
    
    template <typename T>
    class LinkList
    {
    public:
        LinkList();
        ~LinkList();
        bool isListEmpty();
        bool clearList();
        int getListLength();
        int getElemIndex(T &elem);
        bool getListElem(int index,T* elem);
        //bool getListPrevious(int index,T* elem); 
        //bool getListNext(int index,T* elem);
        bool ListInsert(int index,T &elem);
        bool ListDelete(int index,T *elem);
        void ListPrint(void);
    private:
        Node<T> *m_pList;
        int m_iLength;
    };
    
    template <typename T>
    LinkList<T>::LinkList()
    {
        m_pList = new Node<T>;
        m_pList->setData(NULL);
        m_pList->setNext(NULL);
        m_iLength=0;
    }
    
    template <typename T>
    LinkList<T>::~LinkList()
    {
        Node<T> *nextNode = m_pList;
        while(nextNode->getNext()!=NULL)    //delete Node while pointerNext == NULL
        {        
            nextNode=m_pList->getNext();
            delete m_pList;
            m_pList = nextNode;
        }
        delete m_pList;//delete last Node
        m_pList = NULL;
    }
    
    template <typename T>
    bool LinkList<T>::isListEmpty()
    {
        if(m_iLength==0)
            return true;
        return false;
    }
    
    
    template <typename T>
    bool LinkList<T>::clearList()
    {
        if(isListEmpty())
        {
            cout<<"List empty clear fail"<<endl;
            return false;
        }
    
        //delete All node except first node
        Node<T> *nowNode = m_pList->getNext();
        Node<T> *nextNode = m_pList->getNext();
        while(nextNode->getNext()!=NULL)    
        {        
            nextNode=nowNode->getNext();
            delete nowNode;
            nowNode = nextNode;
        }
        delete nowNode;//delete last Node
    
        m_iLength = 0;
        m_pList->setNext(NULL);
        return true;
    }
    
    template <typename T>
    int LinkList<T>::getListLength()
    {
        return m_iLength;
    }
    template <typename T>
    int LinkList<T>::getElemIndex(T &elem)
    {
        Node<T> *tempNode = m_pList;
        for(int i=0;i<m_iLength;i++)
        {
            tempNode = tempNode->getNext();
            if(elem == tempNode->getData())
            {
                return i;
            }
        }
        return -1;
    }
    template <typename T>
    bool LinkList<T>::getListElem(int index,T* elem)
    {
        if(index<0 || index>= m_iLength)
        {
            return false;
        }
    
        Node<T> *tempNode = m_pList;
        for(int i=0;i<=index;i++)
        {
            tempNode=tempNode->getNext();
        }
    
        *elem = tempNode->getData();
        return true;
    }
    
    
    
    template <typename T>
    bool LinkList<T>::ListInsert(int index,T &elem)
    {
        //index out of range
        if(index<0 || index>m_iLength)
        {
            return false;
        }
    
        //
        Node<T> *tempPreNode = m_pList; 
        for(int i=0;i<index;i++)
        {
            tempPreNode = tempPreNode->getNext();
        }
    
        Node<T> *newnode = new Node<T>;    //create a new node
        if(newnode == NULL)
        {
            cout<<"new node create fail"<<endl;
            return false;
        }
        Node<T> *tempNode= tempPreNode->getNext();//save pre node pointer
        tempPreNode->setNext(newnode); //set pre node pointer to new node address
        newnode->setNext(tempNode);//set new node pointer to pre node pointer
        newnode->setData(elem);    //set new node new data
        m_iLength++;
        return true;
    }
    
    template <typename T>
    bool LinkList<T>::ListDelete(int index,T *elem)
    {
        //index out of range
        if(index<0 || index>=m_iLength)
        {
            return false;
        }
    
        //
        Node<T> *tempPreNode = m_pList; //pre node
        for(int i=0;i<index;i++)//find pre node
        {
            tempPreNode = tempPreNode->getNext();
        }
    
        Node<T> * tempNode = tempPreNode->getNext();//save delete point pointer 
        tempPreNode->setNext(tempNode->getNext());//set pre node  point to next node
        *elem = tempNode->getData();
        delete tempNode;
    
        m_iLength--;
        return true;        
    }
    
    template <typename T>
    void LinkList<T>::ListPrint(void)
    {
        if(isListEmpty())
        {
            cout<<"List empty"<<endl;
            return;
        }
        Node<T> *tempNode=m_pList->getNext();
        while(tempNode->getNext() != NULL)
        {        
            tempNode->printData();
            tempNode = tempNode->getNext();
        }
        tempNode->printData();
        cout<<"end"<<endl;
    }
    View Code

    单项链表模板定义完了,我们在main.cpp中使用int类型实例化它、并测试它的功能

    #include <iostream>
    #include <string>
    #include "LinkList.h"
    using namespace std;
    
    int main(void)
    {
        /*insert data check*/
        int data[10]={0,1,2,3,4,5,6,7,8,9};
        LinkList<int> *linklist = new LinkList<int>;
        for(int i=0;i<5;i++)
        {
            linklist->ListInsert(i,data[i]);
        }
        linklist->ListPrint();
    
        /*getElemIndex check*/
        cout<<"getElemIndex:"<<linklist->getElemIndex(data[4])<<endl;
    
        /*getListElem check*/
        int getdata;
        linklist->getListElem(2,&getdata);
        cout<<"getListElem:"<<getdata<<endl;
    
    
        /*delete data check*/
        int deletedata;
        linklist->ListDelete (0,&deletedata);
        cout<<"delete data:"<<deletedata<<endl;
        linklist->ListPrint();
    
        /*clearList check*/
        linklist->clearList();
        linklist->ListPrint();
    
        delete linklist;
        linklist = NULL;
        system("pause");
        return 0;
    }

    运行结果如下:

  • 相关阅读:
    1451. Rearrange Words in a Sentence
    1450. Number of Students Doing Homework at a Given Time
    1452. People Whose List of Favorite Companies Is Not a Subset of Another List
    1447. Simplified Fractions
    1446. Consecutive Characters
    1448. Count Good Nodes in Binary Tree
    709. To Lower Case
    211. Add and Search Word
    918. Maximum Sum Circular Subarray
    lua 时间戳和时间互转
  • 原文地址:https://www.cnblogs.com/HongYi-Liang/p/7172345.html
Copyright © 2020-2023  润新知