數據結構-單向鏈表 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:\r\n");
    for(i=0;i<list->m_iLength;i++)
    {
        tempNode = tempNode->m_iNext;
        printf("%d\r\n",*tempNode);
    }
    printf("end\r\n");
}
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:\r\n");
    for(i=0;i<5;i++)
    {
        if(LinkListInsert(list,i,data[i]))
            printf("Insert succeed:%d\r\n",data[i]);
        else
            printf("Insert fail:%d\r\n",data[i]);
    }
    LinkListPrintAll(list);

    //GetLinkListElemIndex check
    printf("GetLinkListElemIndex:data[3]:%d\r\n",GetLinkListElemIndex(list,data[3]));
    
    //GetListElem check
    GetListElem(list,2,&GetListElemData);
    printf("GetListElem list second data:%d\r\n",GetListElemData);

    //LinkListDelete check
    if(LinkListDelete(list,5,&deletedata))
        printf("LinkListDelete (getData:%d)\r\n",deletedata );
    else
        printf("LinkListDelete fail\r\n");
    LinkListPrintAll(list);

    //LinkListInsertHead and LinkListInsertTail
    printf("LinkListInsertHead:data[7] and LinkListInsertTail:data[8]\r\n");
    LinkListInsertHead(list,data[7]);
    LinkListInsertTail(list,data[8]);
    LinkListPrintAll(list);

    //LinkListDeleteAll check
    printf("LinkListDeleteAll:\r\n");
    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;
}

 

運行結果如下:


免責聲明!

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



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