链表操作二——中间结点的删除等
一:特殊要求的结点删除
问题描述:假设有一个没有头指针的单链表。一个指针指向此单链表中间的一个结点(不是第一个,也不是最后一个)。请将该节点从单链表中删除。
思路:根据题意,似乎很难完成。其实我们可以将当前结点的后续结点的值域赋值给当前结点的值域。然后再删除当前结点的后续结点,即可完成”狸猫换太子“。代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <time.h> 5 6 typedef struct tag 7 { 8 int Nnum_; 9 struct tag *Nnext_; 10 }Node, *pNode; 11 12 13 void link_print(pNode phead) 14 { 15 while(phead != NULL) 16 { 17 printf("%4d", phead->Nnum_); 18 phead = phead->Nnext_; 19 } 20 printf("\n"); 21 } 22 //头插法 23 void link_init_tail(pNode *phead, int size) //传的是地址 24 { 25 pNode pNew = NULL; 26 pNode pTail = NULL; 27 28 while( size > 0) 29 { 30 //申请内存 31 pNew = (pNode)malloc(sizeof(Node)); //注意这里为何不用pNode而用Node,因为sizeof(pNode) = 4 32 //赋值 33 pNew->Nnum_ = rand()%1000; 34 //插入链表 35 if(*phead == NULL) //链表为空时 36 { 37 *phead = pNew;//连接新的结点 38 pTail = pNew; 39 } 40 else//不为空 41 { 42 pTail->Nnext_ = pNew ; //连接新的结点 43 pTail = pNew; //改名字 44 } 45 size --; 46 } 47 } 48 49 int delete_special_pos(pNode *phead) //为了验证结果而将其打印出来,我们采用带有头指针的链表 50 { 51 if(*phead == NULL && (*phead)->Nnext_ == NULL) 52 return 0; 53 int i = 1;//为了叙述方便,我们假设其位置是3 54 55 pNode pCur = *phead; 56 while( i < 3) //使pCur指向第三个结点 57 { 58 pCur = pCur->Nnext_; 59 i ++; 60 } 61 //删除第三个结点的int值 62 pNode pNext = pCur->Nnext_; //建立初始值 63 //我们要把pNext所指向结点int值放到pCur中,然后再删除pNext。此刻就完成了“狸猫换太子” 64 pCur->Nnext_ = pNext->Nnext_; 65 pCur->Nnum_ = pNext->Nnum_; 66 free(pNext); 67 pNext = NULL; //防止野指针的出现 68 return 1; 69 } 70 71 int main(int argc, char const *argv[]) 72 { 73 srand(time(NULL)); 74 pNode phead = NULL; 75 link_init_tail(&phead, 10); 76 link_print(phead); 77 78 printf("ret:%d\n",delete_special_pos(&phead) ); 79 link_print(phead); 80 81 return 0; 82 }
二:编码实现环状单向链表(尾指针直接指向头指针,中间没有空结点),去除连续的重复元素的操作。(2012,人人)
比如:1(头)->2 ->2 ->3 ->3 ->1 ->1(头),去除以后的结果是 1 ->2 ->3(注意头部的 1 也要去掉一个);
思路:
1、如果该链表为空或者长度为1,则直接返回。
2、遍历一次循环单向链表,删除连续的重复的结点;
3、判断最后一个结点是否和第一个结点值相同:
一)若相同,删除最后一个结点,并且返回头结点;
二)若不相同,直接返回头结点。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <time.h> 5 #include <assert.h> 6 7 typedef struct tag 8 { 9 int Nnum_; 10 struct tag *Nnext_; 11 }Node, *pNode; 12 13 14 void link_print(pNode phead, int size) 15 { 16 int i= 1; 17 while(phead != NULL) 18 { 19 printf("%2d", phead->Nnum_); 20 phead = phead->Nnext_; 21 if( ++i > size) 22 break; 23 } 24 printf("\n"); 25 } 26 //尾插法 27 void link_init_tail(pNode *phead, int size) //传的是地址 28 { 29 pNode pNew = NULL; 30 pNode pTail = NULL; 31 32 while( size > 0) 33 { 34 //申请内存 35 pNew = (pNode)malloc(sizeof(Node)); //注意这里为何不用pNode而用Node,因为sizeof(pNode) = 4 36 //赋值 37 //pNew->Nnum_ = rand()%5; 38 pNew->Nnum_ = 1; 39 40 //插入链表 41 if(*phead == NULL) //链表为空时 42 { 43 *phead = pNew;//连接新的结点 44 pTail = pNew; 45 } 46 else//不为空 47 { 48 pTail->Nnext_ = pNew ; //连接新的结点 49 pTail = pNew; //改名字 50 } 51 size --; 52 } 53 //生成一个首尾相连的环 54 pTail->Nnext_ = *phead; 55 } 56 57 pNode unique( pNode phead) 58 { 59 //如果该链表为空或者长度为1,则直接返回。 60 if( phead == NULL || phead->Nnext_ ==NULL) 61 return phead; 62 63 //遍历一次循环单向链表, 64 pNode pCur = phead; 65 pNode pNext = pCur->Nnext_; 66 67 while(pNext != phead) 68 { 69 //删除连续的重复的结点 70 while(pCur->Nnum_ == pNext->Nnum_ && pNext != phead) 71 { 72 pCur->Nnext_ = pNext->Nnext_; 73 free(pNext); 74 pNext= pCur->Nnext_; 75 } 76 77 if( pNext == phead) //判断最后一个结点是否和第一个结点值相同 78 break; 79 //int值不相等-->向后移动 80 pCur = pNext; 81 pNext = pNext->Nnext_; 82 } 83 84 if( pCur->Nnum_ == pNext->Nnum_) 85 { 86 //所有值域全部相同 87 if(pNext == pCur) 88 { 89 printf("All the link's elements are equal\n"); 90 printf("the value is:%d\n",pNext->Nnum_); 91 //free(pNext);// 为什么加上这两句就错了? 92 //pNext = NULL; 93 return pCur; 94 } 95 //存在值域不相同的结点->此时剩余的结点组成一个循环链表 96 pCur->Nnext_ = pNext->Nnext_; 97 free(pNext); 98 return pCur; 99 } 100 //不相等,这时pNext == *phead 101 return pNext; 102 } 103 104 int main(int argc, char const *argv[]) 105 { 106 srand(time(NULL)); 107 pNode phead = NULL; 108 link_init_tail(&phead, 10); //10为初始链表的长度 109 link_print(phead,15); 110 111 pNode pRet = unique(phead); 112 113 link_print(pRet, 10); 114 return 0; 115 }
链表的快慢指针的使用,详见下篇:链表三——快慢指针的使用