数据结构-单向链表 C和C++的实现
数据结构,一堆数据的存放方式。
今天我们学习数据结构中的 链表:
链表的结构:
链表是一种特殊的数组,它的每个元素称为节点,每个节点包括两个部分:
- 数据域:存放数据,此部分与数组相同
- 指针域:存放了下一个节点的地址(单向链表)、存放上一个和下一个节点的地址(双向链表)
链表比数组多了指针域,因为链表结构是通过上一个节点的指针域去找下一个数据,比如有一个链表ABCD四个节点,其中A节点是链表的第一个节点,如果我们要访问D节点里边的数据。操作如下:
- 先通过A节点的指针域找到B节点
- 再通过B节点的指针域找到C节点
- 再通过C节点的指针域找到D节点
- 获取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
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"); }
最后在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中的链表长度参数来删除链表,具体方法是:
- 创建一个deleteNode指针指向头节点的下一个元素(第0号元素);
- 创建nextNode指针指向deleteNode的下一号元素(第1号元素);
- 删除掉deleteNode的内容;
- deleteNode指针指向nextNode的内容(第1号元素);
- 上边的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传入节点的数据部分
- 判断一下传入的参数是否有,有问题则返回0插入失败
- 用malloc申请一个newNode(新的节点);
- 找到第index-1的节点(存放在preNode);
- 找到第index的节点(存放在nextNode);
- 把preNode的Next指针指向newNode;
- 把newNode的Next指针指向nextNode;(到这里已经完成插入节点,原来的index元素变成了index+1号元素)
- 增加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; }
链表类 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; }
单项链表模板定义完了,我们在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; }
运行结果如下: