• 数据结构-单向链表 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;
    }

    运行结果如下:

  • 相关阅读:
    自实现的DNetStopWatch类
    IL Discovery 系列三 《为什么在遍历List<T>对象时同时删除其中项会抛出异常》
    高效的线程安全队列ConcurrentQueue<T>(上)
    .NET中Object.Equals()方法与Object.ReferenceEquals()方法
    麻省理工学院(MIT)的开放课程(OCW)真的不错,其音像资料
    Eclipse快捷键大全
    MyEclipse快捷键大全
    c#单文件上传下载源代码
    Tomcat 配置集锦
    asp.net(C#)多文件上传(源代码)vs2008
  • 原文地址:https://www.cnblogs.com/HongYi-Liang/p/7172345.html
Copyright © 2020-2023  润新知