单链表——基本操作

单链表结构定义

 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    

 

 

posted @ 2020-05-12 18:07  YOLO-in-the-sun  阅读(361)  评论(0编辑  收藏  举报