数据结构模版----单链表SimpleLinkList[带头结点&&面向对象设计思想](C语言实现)

来源:互联网 发布:mac itune 同步铃声 编辑:程序博客网 时间:2024/06/05 05:31
链表中的数据是以节点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示线性表称作线性链表(单链表)

单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。

#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <assert.h>//#define DEBUG// 调试插桩信息宏///版本V0.0.2更新///①将InsertNode重新实现为两个函数//将数据data插入链表的第position个位置//LinkListNode* InsertNode(LinkList *list, int position, ElemType data)//将数据data插入链表的pNode结点的下一个位置个位置//LinkListNode* AddNode(LinkList *list, LinkListNode *prevNode, ElemType data)///②将DelNode重新实现为三个函数//删除链表list中第position个指针//ElemType DeleteNode(LinkList *list, int position)//删除链表list中prevNode结点之后的指针个指针//ElemType SubNode(LinkListNode *prevNode)//删除链表list中currNode指针所指向的那个结点//ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode)/// ③将FindNode重新实现为三个函数//查找到链表list中第position个结点//LinkListNode* FindPosNode(LinkList *list, int position);//在链表list中找到currNode的前一个结点//LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode);//判断结点node指向的区域是不是链表中的结点//int IsNodeInList(LinkList *list, LinkListNode *node);///*//////////////////////////////////////////////////////////////////////////////////带头结点的单链表结构体//////*////////////////////////////////////////////////////////////////////////////typedef int ElemType;// 自定义数据类型//typedef struct LinkListNode*PLinkListNode;// 链表结点指针域// 链表结点数据域typedef struct LinkListNode{ElemTypem_data;// 数据域struct LinkListNode*m_next;// 指针域}LinkListNode;// 带头结点的单项链表typedef struct LinkList{LinkListNode*m_head;// 链表头结点intm_length;// 单链表数据结点个数指针域}LinkList;///*//////////////////////////////////////////////////////////////////////////////////创建和初始化单链表//////创建LinkList* CreatLinkList(void)///初始化void InitLinkList(LinkList *list)///*/////////////////////////////////////////////////////////////////////////////**LinkList* CreatLinkList(void)参数list:指向一个链表指针,此处传入表头地址返回值若成功返回创建好的单链表的指针功能开辟一个单链表数据结构,并初始化头结点,然后将创建好的单链表指针返回注意使用CreateLinkList创建的单链表,需要用DestroyLinkList来销毁以免发生内存泄漏*/LinkList* CreateLinkList(void){LinkList *list = NULL;if((list = (LinkList *)malloc(sizeof(LinkList))) == NULL)// 开辟单链表的空间{// 开辟失败        fprintf(stderr, "not enough memory when CREATE LIST...\n");        exit(EXIT_FAILURE);}InitLinkList(list);// 初始化单链表return list;}/**void InitLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址返回值无功能初始化单链表, 执行以下操作①开辟头结点的空间 ②进行必要的初始化[头结点的初始化和单链表结点数目的初始化]注意使用InitLinkList初始化的单链表(初始化时malloc了头结点m_head的空间)而使用用FinitLinkList来进行后处理(后处理时free了头结点的m_head空间)以免发生内存泄漏*/void InitLinkList(LinkList *list){if((list->m_head = malloc(sizeof(LinkListNode))) == NULL)// 为头结点开辟空间{// 开辟失败        fprintf(stderr, "not enough memory when MALLOC HEAD...");        exit(EXIT_FAILURE);}list->m_head->m_next = NULL;// 初始化只有头结点list->m_head->m_data = 0;// 数据元素个数为0list->m_length = 0;// 数据元素个数为0}///*//////////////////////////////////////////////////////////////////////////////////销毁以及后处理单链表//////销毁用CreateLinkList创建的单链表///void DestroyLinkList(LinkList *list)//////后处理单链表,///void FinitLinkList(LinkList *list)////// 清空单链表中的所有元素///void ClearLinkList(LinkList *list)///*/////////////////////////////////////////////////////////////////////////////**void DestroyLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址返回值无功能销毁用CreateLinkList创建的单链表,执行以下操作①清空单链表②释放头结点③释放单链表注意使用CreateLinkList创建的单链表,需要用DestroyLinkList来销毁以免发生内存泄漏*/LinkList* DestroyLinkList(LinkList *list){ClearLinkList(list);// 清空链表FinitLinkList(list);// 销毁头结点if(list != NULL)// 销毁链表的空间{free(list);list = NULL;}}/**void FinitLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址返回值无功能后处理单链表, 执行以下操作①开辟头结点的空间 ②进行必要的初始化[头结点的初始化和单链表结点数目的初始化]注意使用InitLinkList初始化的单链表(初始化时malloc了头结点m_head的空间)而使用用FinitLinkList来进行后处理(后处理时free了头结点的m_head空间)以免发生内存泄漏*/void FinitLinkList(LinkList *list){assert(list->m_head->m_next == NULL);// 后处理指针针对空链表// assert(list->m_length == 0);if(list->m_head != NULL)// 如果此时头结点空间未被销毁{free(list->m_head);list->m_head = NULL;list->m_length = -1;// 未经初始化的单链表元素个数记为-1}}/**void ClearLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址返回值无功能清空单链表中的所有元素*/void ClearLinkList(LinkList *list){    while(list->m_head->m_next != NULL){        DeleteNode(list, 0);}}///*//////////////////////////////////////////////////////////////////////////////////查找函数//////查找到链表list中第position个结点///LinkListNode* FindPosNode(LinkList *list, int position)//////在链表list中找到currNode的前一个结点///LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode)////// 判断结点node指向的区域是不是链表中的结点///int IsNodeInList(LinkList *list, LinkListNode *node)//////找到数据域为data的结点首次出现的位置并返回结点信息///LinkListNode* FindNodeData(LinkList *list, ElemType data, int *position)///*/////////////////////////////////////////////////////////////////////////////**LinkListNode* FindPosNode(LinkList *list, int position)参数list:指向一个链表指针,此处传入表头地址positon:带查找的链表指针的位置返回值若成功返回指向待查找结点的指针若失败返回NULL功能查找到链表list中第position个结点*/LinkListNode* FindPosNode(LinkList *list, int position){assert(list != NULL);// 链表不能为空assert(position >= -1 && position < list->m_length);// 插入的w位置只能在[-1~length]LinkListNode *pNode= list->m_head;    int pos = -1;    while(pNode != NULL && pos < position)// 遍历单链表,找到第position个结点的位置{pNode = pNode->m_next;pos++;}if(pNode == NULL || pos < position){return NULL;}else{#ifdef DEBUGprintf("Find the %d point SUCCESS...[%p]\n", position, pNode);#endif // DEBUGreturn pNode;}}/**LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode);参数list:指向一个链表指针,此处传入表头地址currNode:待查找的链表指针的位置返回值若成功返回指向待查找结点的指针若失败返回NULL功能在链表list中找到currNode的前一个结点*/LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode){assert(list != NULL);assert(currNode != NULL);LinkListNode *pNode = list->m_head;while(pNode->m_next != NULL && pNode->m_next != currNode){pNode = pNode->m_next;}if(pNode->m_next == currNode)// 查找成功{return pNode;}else// 查找失败{return NULL;}}/**int IsNodeInList(LinkList *list, LinkListNode *node)参数list:指向一个链表指针,此处传入表头地址node:指向待查找的结点的指针返回值若成功 返回结点node在链表中的位置若失败 返回-1功能判断结点node指向的区域是不是链表中的结点*/int IsNodeInList(LinkList *list, LinkListNode *node){assert(list != NULL);// 链表不能为空assert(Node != NULL);// 待查找的指针不能为空LinkListNode *pNode= list->m_head;    int pos = -1;    while(pNode != NULL && pNode != node)// 遍历单链表,找到第position个结点的位置{pNode = pNode->m_next;pos++;}if(pNode == NULL){// 查找成功return -1;}else{// 查找失败#ifdef DEBUGprintf("Find the [%p] point in the first %d pointer of the list...\n", fNode, pos);#endif // DEBUGreturn pos;}}/**LinkListNode* FindData(LinkList *list, ElemType data, , int *position)参数list:指向一个链表指针,此处传入表头地址data:待查找的结点的数据信息返回值若成功 返回结点node在链表中的位置若失败 返回-1功能找到数据域为data的结点首次出现的位置并返回结点信息*/LinkListNode* FindNodeData(LinkList *list, ElemType data, int *position){LinkListNode *node = list->m_head->m_next;int pos = 0;while(node != NULL && node->m_data != data){node = node->m_next;pos++;}*position = pos;// 将出现的位置传递回去return node;// 返回结点的信息}///*//////////////////////////////////////////////////////////////////////////////////插入函数//////将数据data插入链表的prevNode结点的下一个位置个位置///LinkListNode *AddNode(LinkList *list, LinkListNode *prevNode, ElemType data)//////将数据data插入链表的第position个位置///LinkListNode *InsertNode(LinkList *list, int position, ElemType data)///*/////////////////////////////////////////////////////////////////////////////**LinkListNode* AddNode(LinkList *list, LinkListNode *prevNode, ElemType data);参数list:指向一个链表指针,此处传入表头地址prevNode:待插入位置的前一个结点data:待插入结点的数据返回值无功能将数据data插入链表的prevNode结点的下一个位置个位置*/LinkListNode *AddNode(LinkList *list, LinkListNode *prevNode, ElemType data){assert(prevNode != NULL);// 插入点不能是空指针LinkListNode *newNode = NULL;if((newNode = (LinkListNode *)malloc(sizeof(LinkListNode))) == NULL)// 为新结点开辟空间{// 开辟新结点失败fprintf(stderr, "not enough memeory\n");        exit(EXIT_FAILURE);}//else//{// 开辟新结点成功newNode->m_data = data;newNode->m_next = NULL;// 将指针newNode连接在pNode的后面newNode->m_next = prevNode->m_next;prevNode->m_next = newNode;list->m_length++;// 结点数目增加一个list->m_head->m_data++;// 头结点的数据域同样存储着结点总数//}#ifdef DEBUGprintf("The new node is inserted after point pointer[%p]\n", pNode);#endif // DEBUGreturn newNode;}/**void InsertNode(LinkList *list, int position, ElemType data)参数list:指向一个链表指针,此处传入表头地址positon:待插入结点的位置data:待插入结点的数据返回值无功能将数据data插入链表的第position个位置*/LinkListNode *InsertNode(LinkList *list, int position, ElemType data){assert(list != NULL);assert(position >=0 && position < list->m_length + 1);LinkListNode *prevNode = FindPosNode(list, position - 1);// 找到待插入位置的前一个结点LinkListNode *newNode = NULL;// 下面调用InsertPointNode直接将结点插入到pNode结点后面if((newNode = AddNode(list, prevNode, data)) != NULL)// 将新的结点插入到待插入前一个指针的后面{// 插入成功return newNode;// 返回新插入的结点#ifdef DEBUGprintf("Insert the value %d into list at position %d...\n", data, position);#endif // DEBUG}else{return NULL;// 插入失败返回NULL}////以可以使用下面的代码//if((newNode = (LinkListNode *)malloc(sizeof(LinkListNode))) == NULL)// 为新结点开辟空间//{// 开辟新结点失败//fprintf(stderr, "not enough memeory\n");//        exit(EXIT_FAILURE);//}//else//{// 开辟新结点成功//newNode->m_data = data;//newNode->m_next = NULL;////// 将指针newNode连接在pNode的后面//newNode->m_next = prevNode->m_next;//prevNode->m_next = newNode;////list->m_length++;// 结点数目增加一个//list->m_head->m_data++;// 头结点的数据域同样存储着结点总数//}}///*//////////////////////////////////////////////////////////////////////////////////删除函数//////删除链表list中prevNode结点之后的指针个指针///void DeleteNode(LinkList *list, int position)//////删除链表list中prevNode结点之后的指针个指针///ElemType SubNode(LinkList *list, LinkListNode *prevNode)//////删除链表list中prevNode结点之后的指针个指针///ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode)///*/////////////////////////////////////////////////////////////////////////////**void DeleteNode(LinkList *list, int position)参数list:指向一个链表指针,此处传入表头地址positon:待删除结点的位置返回值返回待删除结点的数据域功能删除链表list中prevNode结点之后的指针个指针*/ElemType DeleteNode(LinkList *list, int position){assert(list != NULL);assert(position >=0 && position < list->m_length);LinkListNode *prevNode = FindPosNode(list, position - 1);// 找到第position - 1个结点// 删除pNode的后一个结点LinkListNode *delNode = prevNode->m_next;ElemType delElem = delNode->m_data;prevNode->m_next = delNode->m_next;free(delNode);list->m_length--;// 结点数目减少一个list->m_head->m_data--;// 头结点的数据域同样存储着结点总数return delNode;}/**ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode);参数list:指向一个链表指针,此处传入表头地址positon:待删除结点的位置返回值返回待删除结点的数据域功能删除链表list中prevNode结点之后的指针个指针*/ElemType SubNode(LinkList *list, LinkListNode *prevNode){assert(list != NULL);// 链表不能为空assert(prevNode != NULL);// 待删除结点的前一个位置不能为空assert(IsNodeInList(list, prevNode) != -1);// 待删除位置的前一个结点必须在链表中// 删除pNode的后一个结点LinkListNode *delNode = prevNode->m_next;ElemType delElem = delNode->m_data;prevNode->m_next = delNode->m_next;free(delNode);list->m_length--;// 结点数目减少一个list->m_head->m_data--;// 头结点的数据域同样存储着结点总数return delElem;}/**ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode);参数list:指向一个链表指针,此处传入表头地址positon:待删除结点的位置返回值返回待删除结点的数据域功能删除链表list中prevNode结点之后的指针个指针*/ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode){assert(list != NULL);// 链表不能为空assert(currNode != NULL);// 待删除结点的前一个位置不能为空assert(IsNodeInList(list, currNode) != -1);// 待删除的结点必须在链表中ElemType delElem = -1;// 待删除结点的数据域LinkListNode *delNode = NULL;// 指向将要删除的结点的指针if(currNode->m_next != NULL)// 如果待删除结点不是最后一个结点{// 将currNode的后一个结点delNode作为删除结点,delNode = currNode->m_next;currNode->m_next = delNode->m_next;//从链表中删除delNode// 并将delNode的数据域保存到delNode中delElem = currNode->m_data;// delElem保存currNode的数据域currNode->m_data = delNode->m_data;// 真正删除的结点其实是currNode下一个结点, 因此用currNode保存下一个结点的数据域}else// 否则待删除结点是最后一个结点{// 直接将最后一个结点删除即可, 应该把其前一个结点的指针域赋值为空delNode = currNode;// 下面应该将currnNode的前一个结点的指针域赋值为空[时间复杂度O(n)]LinkListNode *prevNode = FindPrevNode(list, currNode);prevNode->m_next = NULL;}free(delNode);list->m_length--;// 结点数目减少一个list->m_head->m_data--;// 头结点的数据域同样存储着结点总数return delElem;}///*//////////////////////////////////////////////////////////////////////////////////其他函数//////显示单链表的信息///void ShowList(LinkList *list//////删除链表list中prevNode结点之后的指针个指针///void SetNode(LinkList *list, int position, ElemType data)//////获取单链表list第position个结点的数据域/// ElemType GetNode(LinkList *list, int position)//////获取单链表list的长度[即元素个数]///int LengthLinkList(LinkList *list)//////判断当前链表是否是空链表///bool IsEmptyLinkList(LinkList *list)///*/////////////////////////////////////////////////////////////////////////////**void ShowLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址返回值无功能显示单链表的信息*/void ShowList(LinkList *list){// assert(list->m_head != NULL)if(list->m_head ==  NULL)//  单链表可能没有被初始化{fprintf(stderr, "you can't SHOW the list without the list INITLINKLIST...\n");return ;}printf("there are %d data in list\n", list->m_length);if(list->m_length == 0){return ;}LinkListNode *pNode = list->m_head->m_next;// 从头指针开始遍历while(pNode != NULL)//开始遍历单链表{printf("%d  ", pNode->m_data);        pNode = pNode->m_next;}printf("\n");//ElemType data;//for(int pos = 0; pos < list->m_length; pos++)//{//data = GetNode(list, pos);//printf("%d  ", data);//}//printf("\n");}/**void SetNode(LinkList *list, int position, ElemType data)参数list:指向一个链表指针,此处传入表头地址positon :待修改的结点的数据data:待更正的新数据域返回值无功能修改单链表list第position个结点的数据域为data*/void SetNode(LinkList *list, int position, ElemType data){LinkListNode *pNode = FindPosNode(list, position);// 找到单链表的第position个结点pNode->m_data = data;}/**ElemType GetNode(LinkList *list, int position参数list:指向一个链表指针,此处传入表头地址positon :待查询的结点的位置返回值获取到的结点数据功能获取单链表list第position个结点的数据域*/ElemType GetNode(LinkList *list, int position){LinkListNode *pNode = FindPosNode(list, position);// 找到单链表的第position个结点return pNode->m_data;}/**int LengthLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址positon :待查询的结点的位置返回值获取到的结点数据功能获取单链表list的长度[即元素个数]*/int LengthLinkList(LinkList *list){return list->m_length;}/**bool IsEmptyLinkList(LinkList *list)参数list:指向一个链表指针,此处传入表头地址返回值如果单链表是空表,返回true否则返回false功能判断当前链表是否是空链表*/bool IsEmptyLinkList(LinkList *list){return (list->m_length == 0);// return (list->m_head->m_next == NULL);}#define LIST_SIZE 7// 主函数int main(void){int pos;printf("TEST 1...\n");LinkList *plist = CreateLinkList( );// 创建单链表for(int pos = 0; pos < LIST_SIZE; pos++)// 循环向单链表中插入数据{InsertNode(plist, pos, pos + 1);}ShowList(plist);// 插入结束后显示单链表的信息DeleteNode(plist, 0);// 删除第一个元素ShowList(plist);DeleteNode(plist, 1);// 删除第二个元素ShowList(plist);ClearLinkList(plist);// 将单链表清空ShowList(plist);DestroyLinkList(plist);// 将单链表销毁plist = NULL;printf("\n\nTEST 2...\n");LinkList list;InitLinkList(&list);// 初始化单链表for(int pos = 0; pos < LIST_SIZE; pos++)// 训话向单链表中插入数据{InsertNode(&list, pos, pos + 1);}ShowList(&list);// 显示单链表ClearLinkList(&list);// 清空单链表//FinitLinkList(&list);// ERROR== list->m_head->m_next == NULLShowList(&list);printf("\n\nTEST 3...\n");LinkListNode *prevNode = list.m_head;LinkListNode *addNode = NULL;for(int pos = 0; pos < LIST_SIZE; pos++){if((addNode = AddNode(&list, prevNode, pos + 1)) != NULL){            prevNode = addNode;}}ShowList(&list);while(IsEmptyLinkList(&list) != true)// 循环删除单链表中的数据{DeleteCurrNode(&list, list.m_head->m_next);}ShowList(&list);// 显示单链表return EXIT_SUCCESS;}

0 0