- 线性链表
- 静态链表(数组)/动态链表(malloc)
- 循环链表
- 双向链表/单链表
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