严蔚敏版《数据结构 (C语言版)》和《数据结构题集》(三)——单链表

  1. 线性链表
  2. 静态链表(数组)/动态链表(malloc)
  3. 循环链表
  4. 双向链表/单链表
    1 线性链表的基本操作
    顺序存储方式的优点:
    1)随机存取
    2)不需要额外增加空间以表示结点间的逻辑关系
    缺点:
    1)插入删除效率低
    2)只能利用连续空间,不能利用小块空间
    3)静态存储分配。表长变化大时难以确定表长的规模
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #define OVERFLOW -2
  5 
  6 using namespace std;
  7 
  8 typedef int Elemtype;
  9 typedef struct node{
 10 Elemtype data;
 11 struct node *next;
 12 }node,*linklist;
 13 
 14 //建立单链表
 15 //1.头插 2.尾插
 16 void createList_L(linklist &l){
 17 l=(linklist )malloc(sizeof(node));
 18 linklist p=l,q;
 19 int x;
 20 scanf ("%d",&x);
 21 while (x!=-999){
 22 q=(linklist )malloc(sizeof(node));
 23 q->data=x;
 24 p->next=q;
 25 p=q;
 26 scanf ("%d",&x);
 27 }
 28 q->next=NULL;
 29 }
 30 //算法2.11
 31 void createList_Lhead(linklist &l){
 32 l=(linklist )malloc(sizeof(node));
 33 linklist p;
 34 l->next=NULL;
 35 int x;
 36 scanf ("%d",&x);
 37 while (x!=-999){
 38 p=(linklist )malloc(sizeof(node));
 39 p->data=x;
 40 p->next=l->next;
 41 l->next=p;
 42 scanf ("%d",&x);
 43 }
 44 }
 45 void displayList_L(linklist &l){
 46 linklist p=l->next;
 47 while (p!=NULL){
 48 printf ("%d ",p->data);
 49 p=p->next;
 50 }
 51 printf ("
");
 52 }
 53 //查找运算
 54 //1. 按照序号查找 2、按值查找
 55 linklist getElem(linklist &l,int i){
 56 int j=1;
 57 linklist p=l->next;
 58 while (p!=NULL&&j<i){
 59 p=p->next;
 60 j++;
 61 }
 62 return p;
 63 }
 64 linklist getElem_2(linklist &l,Elemtype e){
 65 linklist p=l->next;
 66 while (p!=NULL&&p->data!=e){
 67 p=p->next;
 68 }
 69 if (!p){
 70 printf("没有该元素
");
 71 return NULL;//返回值类型为指针
 72 }
 73 return p;
 74 }
 75 
 76 int listLength(linklist &l){
 77 int count =0;
 78 linklist p=l->next;
 79 while (p){
 80 p=p->next;
 81 count ++;
 82 }
 83 return count;
 84 }
 85 //插入运算
 86 //1.指定节点前、后 2.指定位置前、后
 87 void listInsert_Lafter(linklist &p,Elemtype e){
 88 linklist q;
 89 q=(linklist )malloc (sizeof(node));
 90 q->data=e;
 91 q->next=p->next;
 92 p->next=q;
 93 }
 94 void listInsert_Lbefore(linklist &l,linklist p,Elemtype e){
 95 linklist q=l;
 96 while (q->next!=p) q=q->next;
 97 listInsert_Lafter(q,e);
 98 }
 99 void listInsert_Lbefore_2(linklist &l,linklist p,Elemtype e){
100 //仍然将Q插到P的后面,然后交换数据域!很聪明的前插方式,不用循环查找前驱了
101 linklist q;
102 q=(linklist )malloc (sizeof(node));
103 q->next=p->next;
104 p->next=q;
105 q->data=p->data;
106 p->data=e;
107 }
108 //在第i个元素之前插入e
109 int listInsert_L_i(linklist &l,int i,Elemtype e){
110 int j=0;//必须从头结点开始
111 linklist p=l;
112 //if (i<1||i>listLength(l)){
113 //printf("position error !
");
114 //return 0;
115 //}
116 while (p&&j<i-1) {
117 //为什么这里是P?因为I可以是1--length+1
118 p=p->next;
119 j++;
120 }
121 if (!p||j>i-1){
122 //p为空是i太大,j>i-1是i太小
123 printf("position error 
");
124 return 0;
125 }
126 linklist q;
127 q=(linklist )malloc (sizeof(node));
128 q->data=e;
129 q->next=p->next;
130 p->next=q;
131 return 1;
132 }
133 //在值为y的结点前插入e
134 int listInsert_L_y(linklist &l,Elemtype y,Elemtype e){
135 linklist p=l;
136 while (p->next&&p->next->data!=y){
137 //如果P->next为空则Y元素必定不存在,注意这里与上一个插入的区别
138 p=p->next;
139 }
140 if (!p){
141 printf ("元素不存在
");
142 return 0;
143 }
144 linklist q;
145 q=(linklist )malloc (sizeof(node));
146 q->data=e;
147 q->next=p->next;
148 p->next=q;
149 
150 }
151 //删除
152 //1、给定结点2、给定位置
153 //注意:1、被删除结点是否存在2、释放存储空间
154 int listDelete_L(linklist &l,linklist &p){
155 linklist q=l;
156 while (q&&q->next!=p) q=q->next;
157 if (!q) {
158 printf ("结点不存在
");
159 return 0;
160 }
161 q->next=p->next;
162 free(p);
163 return 1;
164 }
165 int listDelete_L_i(linklist &l,int i,Elemtype &e){
166 linklist p=l;
167 int j=0;
168 while (p->next&&j<i-1){
169     //查找第I-1个结点
170 p=p->next;
171 j++;
172 }
173 if (!p->next||j>i-1){
174 printf ("position error
");
175 return 0;
176 }
177 linklist q=p->next;
178 p->next=q->next;
179 e=q->data;
180 free(q);
181 return 1;
182 }
183 int main()
184 {
185 linklist l;
186 createList_L(l);
187 displayList_L(l);
188 Elemtype e;
189 listDelete_L_i(l,3,e);
190 displayList_L(l);
191 
192     return 0;
193 }

练习题,不调用函数

  1 //1.删除单链表l中的重复结点
  2 int deleteDupNode(linklist &l){
  3 linklist p=l->next,q=p,k;
  4 if (!p) 
  5 return 0;//空链直接返回
  6 while (p->next){
  7 while (q->next){
  8 if (q->next->data==p->data){
  9 k=q->next;
 10 q->next=k->next;
 11 free(k);
 12 }
 13 else 
 14 q=q->next;
 15 }
 16 p=p->next;
 17 q=p;
 18 }
 19 
 20 return 1;
 21 }
 22 //2.逆置单链表l
 23 void flipL(linklist &l){
 24 linklist p=l->next,q=p;
 25 l->next=NULL;//分离头结点
 26 while (p){
 27 p=p->next;//q指向当前断链的头结点,p指向待分离链的头结点
 28 q->next=l->next;
 29 l->next=q;
 30 q=p;
 31 }
 32 }
 33 //3.非递增单链表ab,融合成非递增有序单链表c
 34 linklist unionL(linklist &a,linklist &b){
 35 linklist c=a;
 36 linklist pa=a->next,pb=b->next,pc=c;
 37 while (pa&&pb){
 38 if (pa->data > pb->data){
 39 pc->next=pb;
 40 pc=pc->next;//pc始终指向C链的尾
 41 pb=pb->next;
 42 }
 43 else {
 44 pc->next=pa;
 45 pc=pc->next;//pc始终指向C链的尾
 46 pa=pa->next;
 47 }
 48 }
 49 if(pa){
 50 pc->next=pa;
 51 }
 52 if(pb){
 53 pc->next=pb;
 54 }
 55 //pc->next=pa?pa:pb;
 56 free(b);
 57 return c;
 58 }
 59 //5.对不带头结点的L就地逆置
 60 void createList_Lnohead(linklist &l){
 61 l=NULL;
 62 linklist p,q;
 63 int x;
 64 scanf ("%d",&x);
 65 while (x!=-999){
 66 q=(linklist)malloc(sizeof(node));
 67 q->data=x;
 68 if (!l){
 69 p=q;l=q;
 70 }else{
 71 p->next=q;
 72 q->next=NULL;
 73 p=q;
 74 }
 75 scanf ("%d",&x);
 76 }
 77 }
 78 void displayList_Lnohead(linklist &l){
 79 linklist p=l;
 80 while (p!=NULL){
 81 printf ("%d ",p->data);
 82 p=p->next;
 83 }
 84 printf ("
");
 85 }
 86 void flip_Lnohead(linklist &l){
 87 linklist p,q;
 88 q=p=l;//可以连续赋值,从左到右
 89 l=NULL;//分离头指针
 90 while (p){
 91 p=q->next;
 92 q->next=l;
 93 l=q;
 94 q=p;
 95 }
 96 }
 97 //6.对单链表l进行排序
 98 // 冒泡for 
 99 void sort_Lfor(linklist &l){
100     linklist p,q;
101     p=l->next;q=p->next;
102     int t;
103 for (int i=0;i<listLength(l)-1;i++){
104 for (int j=0;j<listLength(l)-1-i;j++){
105 if (p->data >q->data){
106 t=p->data;
107 p->data=q->data;
108 q->data=t;
109 }
110 p=p->next;
111 q=q->next;
112 }
113 p=l->next;
114 q=p->next;
115 }
116 }
117 //7.单链表la,lb存储两个字符串,找出la中第一个不在lb中出现的字符
118 int haha(linklist &la,linklist &lb){
119 linklist pa=la->next;
120 int locate_L(linklist &l,linklist p);
121 while (pa){
122 if (locate_L(lb,pa))
123 pa=pa->next;
124 else
125 return pa->data;
126 }
127 }
128 int locate_L(linklist &l,linklist p){
129 linklist q=l->next;
130 while (q){
131 if (q->data==p->data)
132 return 1;
133 q=q->next;
134 }
135 return 0;
136 }
137 //8.递增有序la,lb,求交集lc
138 linklist jiaoji(linklist &la,linklist &lb){
139 linklist pa=la->next,pb=lb->next,lc,pc;
140 lc=(linklist )malloc(sizeof(node));lc->next=NULL;
141 pc=lc;
142 while (pa&&pb){
143 //如果两个元素相等则连接到lc上,否则比较大小后后移较小元素
144 if (pa->data > pb->data)
145 pb=pb->next;
146 if (pa->data < pb->data)
147 pa=pa->next;
148 if (pa->data==pb->data){
149 pc=(linklist )malloc (sizeof(node));
150 pc->data=pa->data;
151 pc->next=lc->next;
152 lc->next=pc;
153 pa=pa->next;pb=pb->next;
154 }
155 }
156 return lc;
157 }
158 //9.两个字符串la/lb,判断lb是否是la的子串(一个字符串中若干的字符称为子串)
159 int haha(linklist &la,linklist &lb){
160 linklist pa=la->next,pb=lb->next;
161 while (pa&&pa->data!=pb->data) pa=pa->next;
162 if (!pa) {
163 printf ("no
");
164 return 0;
165 }
166 while (pb&&pa->data==pb->data){
167  pb=pb->next;pa=pa->next;
168 }
169 if (!pb)printf ("yes
");
170 else printf ("no
");
171 return 1;
172 }

这里写图片描述

 1 //10.
 2 int DeleteandInsert(linklist &la,linklist &lb,int i,int j,int len){
 3 if (i<0||j<0||len<0) return 0;
 4 linklist p=la,q,s,t;
 5 s=lb;
 6 int k=0;
 7 while (k<i&&p){
 8 p=p->next;k++;
 9 }//P指向第I个元素
10 if (!p) return 0;
11 q=p;
12 k=0;
13 while(k<len&&q){
14 q=q->next;k++;
15 }//q指向被删除的最后一个元素
16 if (!q) return 0;
17 k=0;
18 while(k<j-1&&s){
19 s=s->next;k++;
20 }//s指向被插入元素的前驱
21 if (!s) return 0;
22 t=s->next;
23 s->next=p->next;
24 p->next=q->next;
25 q->next=t;
26 return 1;
27 }
28 //11.删除单调递增链表l中所有值大于min并且小于max的元素(如果存在这样的元素的话)
29 //同时删除被删结点空间
30 void deletel(linklist &l,int min,int max){
31 linklist p=l,q;
32 while (p->next){
33 if (p->next->data>min&&p->next->data < max){
34 q=p->next;
35 p->next=q->next;
36 free(q);
37 }else
38 p=p->next;
39 if (!p)
40 break;
41 }
42 }

方法二:

 1 int deletel(linklist &l,int min,int max){
 2 linklist p=l,q;
 3 while (p->next->data<=min&&p) p=p->next;
 4 //找到第一个被删除结点的前驱
 5 if (!p) return 0;
 6 q=p->next;
 7 while (q&&q->data<max) q=q->next;
 8 //这里q&&q->data与q->Data&&q不同,后者会报错,因为当Q指向NULL时
 9 //q->Data为错误的表达式
10 //q指向第一个不被删除的元素
11 p->next=q;
12 return 1;
13 }
14 //12.删除递增表L中所有值相同的多余元素
15 void deletel(linklist &l){
16 linklist p=l->next,q=p->next;
17 while (q){
18 if (p->data==q->data){
19 p->next=q->next;
20 free(q);
21 q=p->next;
22 }else {
23 p=p->next;
24 q=q->next;
25 }
26 }
27 }

这里写图片描述

 1 void mergeAandB(linklist &la,linklist &lb,linklist &lc){
 2 linklist pa=la->next,pb=lb->next;
 3 linklist qa=pa->next,qb=pb->next;
 4 lc=la;
 5 while (qa&&qb){
 6 pa->next=pb;
 7 pb->next=qa;
 8 pa=qa;
 9 pb=qb;
10 qa=pa->next;
11 qb=pb->next;
12 }
13 if (!qa){
14 pa->next=pb;
15 }
16 if (!qb){
17 pb->next=pa;
18 }
19 }

这里写图片描述

 1 //分析:本算法的思想是,按从小到大的顺序依次把A和B的元素
 2 //插入新表的头部pc处,最后处理A或B的剩余元素.
 3 void reverse_merge(linklist &la,linklist &lb,linklist &lc){
 4 linklist pa=la->next,pb=lb->next,pc,t;
 5 pc=NULL;
 6 while (pa&&pb){
 7 if (pa->data < pb->data ){
 8 t=pa->next;
 9 pa->next=pc;
10 pc=pa;
11 pa=t;
12 }
13 else {
14 t=pb->next;
15 pb->next=pc;
16 pc=pb;
17 pb=t;
18 }
19 }
20 while (pb){
21 t=pb->next;
22 pb->next=pc;
23 pc=pb;
24 pb=t;
25 }
26 while (pa){
27 t=pa->next;
28 pa->next=pc;
29 pc=pa;
30 pa=t;
31 }
32 lc=la;
33 lc->next=pc;
34 free(pb);
35 
36 }

28.

 1 //8.递增有序la,lb,求交集lc
 2 linklist jiaoji(linklist &la,linklist &lb){
 3 linklist pa=la->next,pb=lb->next,lc,pc;
 4 lc=(linklist )malloc(sizeof(node));lc->next=NULL;
 5 pc=lc;
 6 while (pa&&pb){
 7 //如果两个元素相等则连接到lc上,否则比较大小后后移较小元素
 8 if (pa->data > pb->data)
 9 pb=pb->next;
10 else
11 if (pa->data < pb->data)
12 pa=pa->next;
13 else{
14 if (pc->data!=pa->data){
15 pc=(linklist )malloc (sizeof(node));
16 pc->data=pa->data;
17 pc->next=lc->next;
18 lc->next=pc;
19 }
20 pa=pa->next;pb=pb->next;
21 }
22 
23 }
24 return lc;
25 }
26 //2.30 对于A,删去即在b又在c中出现的元素
27 void lalblc(linklist &la,linklist &lb,linklist &lc){
28 linklist pa=la,pb=lb->next,pc=lc->next,t;
29 while (pa->next&&pb&&pc){
30 if (pb->data > pc->data)
31 pb=pb->next;
32 else
33 if (pb->data < pc->data)
34 pc=pc->next;
35 else
36 {
37     if (pa->next->data < pb->data)
38     pa=pa->next;
39     else{
40     while (pa->next->data == pb->data)
41     {
42     t=pa->next;
43     pa->next=t->next;
44     free(t);
45     }
46     pb=pb->next;pc=pc->next;
47 }
48 }
49 }
50 }

//思路:
1.对b和c进行比较:不等时较小数后移;相等时再对a进行比较:a小时移动a,a大时bc移动,相等时对a进行删除。注意这里用while判断pa->next->data == pb->data,因为a中可能有重复的被删除元素。

2)

 1 void LinkList_Intersect_Delete(LinkList &A,LinkList B,LinkList C)//在链表结构上重做上题
 2 {
 3   p=B->next;q=C->next;r=A-next;
 4   while(p&&q&&r)
 5   {
 6     if(p->data<q->data) p=p->next;
 7     else if(p->data>q->data) q=q->next;
 8     else
 9     {
10       u=p->data; //确定待删除元素u
11       while(r->next->data<u) r=r->next; //确定最后一个小于u的元素指针r
12       if(r->next->data==u)
13       {
14         s=r->next;
15         while(s->data==u)
16         {
17           t=s;s=s->next;free(t); //确定第一个大于u的元素指针s
18         }//while
19         r->next=s; //删除r和s之间的元素
20       }//if
21       while(p->data=u) p=p->next;
22       while(q->data=u) q=q->next;
23     }//else
24   }//while
25 }//LinkList_Intersect_Delete 
 
原文地址:https://www.cnblogs.com/twomeng/p/9476537.html