单链表——基本操作
单链表结构定义
1 //注意:所有对链表的结点操作都用变量节点pMove来完成,实现灵活遍历等使用 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 typedef char elemType; 7 typedef struct NodeList 8 { 9 10 char element;//数据区域 11 struct NodeList *next;//指针域 12 }Node;//结点定义+变量定义
初始化带头结点的单链表(均是对指针的定义,因此传入指针的地址,即地址的地址**)
1 //1.初始化带头结点的单链表 2 void InitialList(Node **pNode){ 3 4 //个人建议每一次malloc分配内存空间后,都要进行判断分配是否成功,也即判断是否为空; 5 //此时的这个pNode就是一个头结点; 6 //初始化成功后,其实相当于是一个正常的链表了; 7 *pNode = (Node *)malloc(sizeof(Node)); 8 if (*pNode == NULL) { 9 printf("\n%s函数执行,内存分配失败,初始化单链表失败\n",__FUNCTION__); 10 }else{ 11 12 (*pNode)->next = NULL; 13 printf("\n%s带头结点的单链表初始化完成\n",__FUNCTION__); 14 } 15 }
创建带头结点的单链表
1 //2.创建带头结点的单链表 2 void CreateList(Node *pNode){ 3 4 /** 5 * 就算一开始输入的数字小于等于0,带头结点的单链表都是会创建成功的,只是这个单链表为空而已,也就是里面除了头结点就没有其他节点了。 6 */ 7 Node *pInsert; 8 Node *pMove; 9 int i; 10 pInsert = (Node *)malloc(sizeof(Node));//需要检测分配内存是否成功 pInsert == NULL ? 11 memset(pInsert, 0, sizeof(Node));//用于为占内存大的数据结构如数组、结构体快速初始化 12 pInsert->next = NULL; 13 scanf("%c",&(pInsert->element));//先初始化一个首元节点pInsert 14 15 pMove = pNode;//创建一个专门用来遍历结点的结点指针pMove,首先从头节点开始遍历 16 17 for( i=0;i<5;i++) 18 { 19 20 pMove->next = pInsert;//将刚才初始化的首元节pInsert点连接到头节点pMove后面 21 pMove = pInsert;//遍历结点指针pMove转移到首元节点上 22 23 pInsert = (Node *)malloc(sizeof(Node)); //需要检测分配内存是否成功 pInsert == NULL ? 24 memset(pInsert, 0, sizeof(Node)); 25 pInsert->next = NULL; 26 scanf("%c",&(pInsert->element));//又创建了新的结点 27 28 } 29 30 31 printf("\n%s带头结点的单链表创建成功\n",__FUNCTION__); 32 }
memset功能函数:
函数原型是:void *memset(void *s, int ch, size_t n);
函数功能是:将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为指向s的指针,它是对较大的结构体或数组进行清零操作的一种最快方法。
头文件是:<memory.h>或<string.h>
memset函数通常用来对一块已经分配地址的内存进行初始化,并且通常初始化为0或者字符'\0'(实际上是一样的)
打印链表
1 //3.打印带头结点的单链表 2 void PrintList(Node *pNode){ 3 /** 4 * 注意这里,如果单链表为空(只有一个头结点),我也让它打印(打印成功)。只是里面没有元素,打出来是空的而已,所以在控制台上就是一行空的; 5 */ 6 Node *pMove;//创建遍历节点的结点变量 7 pMove = pNode->next;//从首元结点(即头节点pNode后面->next的结点)开始遍历 8 while (pMove != NULL) 9 { 10 printf("%c",pMove->element); 11 pMove = pMove->next;//继续后移 12 } 13 14 15 }
清除链表
1 //4.清除链表表中的所有元素,即释放所有节点(除了头结点),使之成为一个空表 2 void ClearList(Node *pNode){ 3 4 Node *pMove; 5 pMove = pNode->next;//从首元结点开始遍历 6 while (pMove != NULL) 7 { 8 9 pNode->next = pMove->next;//每次删首元之前先重设置新的首元(即要删除首元的下一个节点) 10 free(pMove);//删首元 11 pMove = pNode->next; 12 } 13 14 printf("\n%s函数执行,清空带头结点的链表成功\n",__FUNCTION__); 15 }
返回链表长度
1 //5.返回带头结点的单链表的长度 2 int SizeList(Node *pNode){ 3 /** 4 * 当只有一个头结点的时候,size = 0;头节点不计算到链表长度中。 5 */ 6 int i = 0; 7 Node *pMove; 8 pMove = pNode->next;//首元开始遍历 9 while (pMove != NULL) { 10 i++; 11 pMove = pMove->next; 12 } 13 14 printf("\n%s带头结点的单链表h的长度为:%d\n",__FUNCTION__,i); 15 16 return i; 17 }
判断链表是否为空
1 //6.判断带头结点的单链表是否为空,为空则返回1,否则返回0 2 int IsEmptyList(Node *pNode){ 3 /** 4 * 当只有一个头结点的时候,该链表就为空 5 */ 6 if (pNode->next == NULL) { 7 printf("\n%s带头结点的链表h为空\n",__FUNCTION__); 8 return 1; 9 } 10 11 printf("\n%s带头结点的链表h非空\n",__FUNCTION__); 12 13 return 0; 14 }
查找具体位置节点元素
1 //7.返回单链表中第pos个结点中的元素,若返回-1,表示没有找到 2 int GetElement(Node *pNode,int pos){ 3 4 int i = 1; 5 6 Node *pMove; 7 pMove = pNode->next;//首元结点开始 8 9 while (pMove != NULL) //尾结点之前 10 { 11 if (i == pos) 12 { 13 14 printf("\n%spos=%d位置的值是%c\n",__FUNCTION__,pos,pMove->element); 15 return pMove->element; 16 } 17 18 i++; 19 pMove = pMove->next; 20 } 21 22 printf("\n%s函数执行,在pos=%d位置没有找到值\n",__FUNCTION__,pos); 23 return -1; 24 }
查找给定元素节点位置
1 //8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL 2 elemType* GetElemAddr(Node *pNode,char x){ 3 4 Node *pMove; 5 pMove = pNode->next; 6 7 while (pMove != NULL) { 8 if (pMove->element == x) { 9 printf("\n%s查找到x=%c的内存地址为:0x%x\n",__FUNCTION__,x,&(pMove->element)); 10 return &(pMove->element); 11 } 12 pMove = pMove->next; 13 } 14 15 printf("\n%s函数执行,在带头结点的单链表中没有找到x=%d的值,无法获得内存地址\n",__FUNCTION__,x); 16 17 return NULL; 18 }
修改节点元素
1 //9.把单链表中第pos个结点的值修改为x的值 2 Node* ModifyElem(Node *pNode,int pos,int x){ 3 4 int i = 1; 5 Node *pMove; 6 pMove = pNode->next; 7 while (pMove != NULL) { 8 if (i == pos) { 9 pMove->element = x; 10 printf("\n%s函数执行,把pos=%d位置的值改为%d成功\n",__FUNCTION__,pos,x); 11 return pNode; 12 } 13 i++; 14 pMove = pMove->next; 15 } 16 printf("\n%s函数执行,链表为空或者输入pos值非法,修改值失败\n",__FUNCTION__); 17 18 return pNode; 19 }
头插法(常用于向链表中添加结点元素)
1 //10.向单链表的表头插入一个元素 2 Node *InsertHeadList(Node *pNode,int x) 3 { 4 5 Node *pInsert; 6 pInsert = (Node *)malloc(sizeof(Node)); 7 memset(pInsert, 0, sizeof(Node)); 8 pInsert->element = x; 9 10 pInsert->next = pNode->next; 11 pNode->next = pInsert; 12 13 printf("%s在表头插入元素%d成功\n",__FUNCTION__,x); 14 return pNode; 15 }
尾插法
1 // 11.向单链表的末尾添加一个元素 2 Node *InsertTailList(Node *pNode,int x){ 3 4 Node *pMove; 5 Node *pInsert; 6 7 pInsert = (Node *)malloc(sizeof(Node)); 8 memset(pInsert, 0, sizeof(Node)); 9 pInsert->element = x; 10 pInsert->next = NULL;//先为要插入的元素创建结点,由于差在尾部所以新的节点指针域为空指针NULL(比以往多了一步) 11 12 pMove = pNode; 13 while (pMove->next != NULL)//找尾指针 14 { 15 pMove = pMove->next; 16 } 17 pMove->next = pInsert; 18 19 20 21 return pNode; 22 }
删除元素
1 //12.从单链表中间删除元素 2 Node *DeleteRand(Node *pNode,int index) 3 { 4 int e; 5 Node *pMove; 6 Node *q; 7 int i; 8 pMove = pNode; 9 10 for(i=0;i<index-1;i++) 11 { 12 pMove=pMove->next; 13 } 14 q=pMove->next; 15 e=q->element; 16 pMove->next=q->next; 17 18 free(q); 19 printf("\n%s在表间第%d位置删除元素成功\n",__FUNCTION__,index); 20 21 return pNode; 22 }
插入元素
1 //13.向链表中间插入一个元素 2 Node *InsertRand(Node *pNode,int index,int a) 3 { 4 Node *pInsert; 5 Node *pMove; 6 int i; 7 8 pInsert = (Node *)malloc(sizeof(Node)); 9 memset(pInsert, 0, sizeof(Node)); 10 pInsert->element = a; 11 12 13 pMove = pNode; 14 15 16 for(i=0;i<index-1;i++) 17 { 18 pMove=pMove->next; 19 } 20 pInsert->next=pMove->next; 21 pMove->next=pInsert; 22 printf("\n%s在表间第%d位置插入元素%c成功\n",__FUNCTION__,index,a); 23 ; 24 return pNode; 25 }
主函数测试(注意用头插法输入元素)
1 int main(int argc, const char * argv[]) 2 { 3 4 Node *pList; 5 6 InitialList(&pList); 7 8 InsertTailList(pList,'a'); 9 InsertTailList(pList,'b'); 10 InsertTailList(pList,'c'); 11 InsertTailList(pList,'d'); 12 InsertTailList(pList,'e'); 13 PrintList(pList); 14 SizeList(pList); 15 16 IsEmptyList(pList); 17 18 GetElement(pList, 3); 19 20 GetElemAddr(pList, 'a'); 21 22 InsertRand(pList,4,'f'); 23 PrintList(pList); 24 25 DeleteRand(pList,3); 26 PrintList(pList); 27 28 29 30 31 32 ClearList(pList); 33 PrintList(pList); 34 35 return 0; 36 } 37 38