③.链表

一:定义

链表是一系列不存在内存中相连的结构组成。每一个结构均含有表元素和指向包含该元素后继元素的结构的指针:Next指针。最后一个单元的Next指向NULL

为了方便,我们使用表头(header)或哑节点(dummy node)来指向第一个节点

 

二:操作

具体链表例程见代码

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct Node *Position;
 5 typedef struct Node *List;
 6 
 7 struct Node{      //链表节点定义
 8     int Element;
 9     Position Next;
10 };
11 
12 void CreateList(List L){
13     int a;
14     Position pre,cur;
15     pre = cur = L;
16     scanf_s("%d", &a);
17     while (a != -1){
18         cur = (Position)malloc(sizeof(struct Node));
19         cur->Element = a;
20         pre->Next = cur;
21         pre = cur;
22         scanf_s("%d", &a);
23     }
24     cur->Next = NULL;   //不忘
25 }
26 
27 void PrintList(List L){
28     Position P;
29     P = L->Next;
30     while (P != NULL){
31         printf("%d ", P->Element);
32         P = P->Next;
33     }
34 }
35 int isEmpty(List L){
36     return L->Next==NULL;
37 }
38 
39 int isLast(Position P, List L){
40     return P->Next == NULL;
41 }
42 
43 Position Find(int X, List L){
44     L = L->Next;
45     while (L != NULL&&L->Element != X){
46         L = L->Next;
47     }
48     return L;
49 }
50 
51 Position FindPrevious(int X, List L){
52     while (L->Next != NULL&&L->Next->Element != X){
53         L = L->Next;
54     }
55     return L;
56 }
57 
58 void Delete(int X, List L){
59     Position Temp;
60     Position P = FindPrevious(X, L);
61     if (!isLast(P, L)){
62         Temp = P->Next;
63         P ->Next = P->Next->Next;
64         free(Temp);
65     }
66 }
67 
68 void Insert(int X, Position P){
69     Position Temp = (Position)malloc(sizeof(struct Node));
70     Temp->Next = P->Next;
71     P->Next = Temp;
72     Temp->Element = X;
73 }
74 
75 void DeleteList(List L){
76     Position Temp, P;
77     P = L->Next;
78     while (P != NULL){
79         Temp = P->Next;
80         free(P);
81         P = Temp;
82 
83     }
84     L->Next = NULL;  //不忘
85 
86 
87 
88 }
View Code

 

唯一要注意的就是链表末节点->Next=NULL这句不要忘记

 

 

 三:应用

①计数排序:

   如果我们有N个整数,范围从1到M,则我们可以有M个空位置,也就是留置一个数组,称为Count,大小为M,初始化为0.当Ai读入时,Count[Ai]加1,等全部输入读进后,扫描一遍数组就可以打印输出排好序的表。 时间复杂度:O(M+N)

    A是原始数据, C是每个数据重复了几次,相当于Count数组,C’是Count[i]+Count[i-1], 然后逆序把数字一个个重新填放入B数组,就是排好序的啦,具体代码实现见基数排序方法二。

②基数排序:

    举例来说明:假设我们有10个数,范围在0-999之间,这样我们就不能用计数排序,因为M太大了。所以我们就想用多趟计数排序。并且,此时是用最低位优先的方式进行计数排序。

    eg:我们现在有0,1,512,343,64,125,216,27,8,729 十个数:

第一次:(按个位排序)

           然后再按照顺序收起来:0,1,512,343,64,125,216,27,8,729

第二次:(按十位排序)

           然后再按照顺序收起来:0,1,8,512,216,125,27,729,343,64

第三次:(按百位排序)

这次收起来就排好序了:0,1,8,27,64,125,216,343,512,729

 

时间复杂度:O(P(N+B)) P是排序趟数,N是排序元素的个数,B是Count

 

代码一:

这个使用一个二维数组当做一个个桶,每个桶的第一个数据代表桶内有几个数字,初始置为0。

 1 int GetDigit(int x, int d){  //取得x的第d位数,个位为第1位数依次递增
 2     int a[10] = { 0,1, 10, 100, 1000 };
 3     
 4     return (x / a[d])% 10;
 5 }
 6 
 7 
 8 void Radix_Sort(int *a, int length){
 9     int Bucket[10][100]; //假设一个桶最多能装100个数据
10     int i, num,j, k = 0;
11     for (num = 1; num < 4; num++){
12         k = 0;
13         for (i = 0; i < 10; i++){
14             Bucket[i][0] = 0; //这位记录第i个桶有多少个数据
15         }
16         for (i = 0; i < length; i++){
17             Bucket[GetDigit(a[i], num)][++Bucket[GetDigit(a[i], num)][0]] = a[i]; //把数据放到相应的桶中
18         }
19         
20         for (i = 0; i < 10; i++){  //从桶中回收数据
21             for (j = 1;j <= Bucket[i][0]; j++){
22                 a[k++] = Bucket[i][j];
23             }
24         }
25     }
26 }
View Code

 

代码二:

这个就完全用到的是计数排序的实现方法,用了一个Count数组。 就是计数排序重复来个几次。

 1 int GetDigit(int x, int d){  //取得x的第d位数,个位为第1位数依次递增
 2     int a[10] = { 0,1, 10, 100, 1000 };
 3     
 4     return (x / a[d])% 10;
 5 }
 6 
 7 
 8 void Radix_Sort(int *a, int length){
 9     int Count[10]; //Count数组是每个桶里有多少个数字
10     int Bucket[10];
11     int i, j; 
12     for (j = 1; j < 4; j++){
13         for (i = 0; i < 10; i++){  //初始置零
14             Count[i] = 0;
15         }
16         for (i = 0; i < length; i++){
17             Count[GetDigit(a[i], j)]++;
18         } 
19         for (i = 1; i < 10; i++){  //这一步就很像计数排序的方法了
20             Count[i] += Count[i - 1];
21         }
22         for (i = length - 1; i >= 0; i--){   
23             Bucket[--Count[GetDigit(a[i], j)]] = a[i];
24         }
25         for (i = 0; i < 10; i++){
26             a[i] = Bucket[i];
27         }
28     }
29 }
View Code

 

四.链表的游标实现

如果有些语言没有指针,那链表不就没有next指针指来指去了吗!所以这里我们就有游标(cursor)实现法:

     我们用数组下标代表地址,所以需要有一个全局的结构体数组。

  比如这张图:

对于Next,0代表的指针是null.然后这张表显示了两个链表,分别是3-7-8-2:cdf 以及:5-10-1-9:abe

然后0-6-4-0代表的是没分配出去的地址:therefore

引出在游标实现中的Malloc和free:

malloc:要新给出一个地址,所以将表头后面的第一个元素删除,按照上表就是0-4-0,如果没有空间可以用了,那返回就是0

free:回收一个,放到最前面:(比如回收8)就是0-8-6-4-0

 

 

 

 

一些习题:

3.5:

L和P已经排序,求L∪P

 1 void  Union(List L, List P){
 2     List Final = (List)malloc(sizeof(struct Node));//最终并集的结果
 3     Final->Next = NULL;
 4     L = L->Next; P = P->Next;
 5     while (L != NULL&&P != NULL){
 6         if (L->Element > P->Element){
 7             Insert(L->Element, Final);
 8             L = L->Next;
 9         }
10         else if (L->Element < P->Element){
11             Insert(P->Element, Final);
12             P = P->Next;
13         }
14         else{
15             Insert(P->Element, Final);
16             L = L->Next; P = P->Next;
17         }
18 
19     }
20     while (L != NULL){
21         Insert(L->Element, Final);
22         L = L->Next;
23     }
24     while (P != NULL){
25         Insert(P->Element, Final);
26         P = P->Next;
27     }
28 }
View Code

 

3.12:

反转单链表 用O(N)的时间。

如果用栈的话就要用O(N)的空间,不用栈的话只要常数附加空间

 1 法1:
 2     List pre, temp, temp1;
 3     List cur = (List)malloc(sizeof(struct Node));
 4     CreateList(cur);
 5     PrintList(cur); printf("\n");
 6     pre = NULL; temp1 = cur; cur = cur->Next;
 7     while (cur != NULL){
 8         temp = cur->Next;
 9         cur->Next = pre;
10         pre = cur;
11         cur = temp;
12     }
13     temp1->Next = pre;
14     
15 
16 
17 
18 
19 法2:
20     //用栈 卧槽
21     int top = -1; List temp1, temp;
22     List cur = (List)malloc(sizeof(struct Node));
23     temp = temp1 = cur;
24     CreateList(cur);
25     PrintList(cur); printf("\n");
26     Position stack[200];
27     cur = cur->Next;
28     while (cur != NULL){
29         stack[++top] = cur;
30         cur = cur->Next;
31     }
32     while (top != -1){
33         temp->Next = stack[top--];
34         temp = temp->Next;
35 
36     }
37     temp->Next = NULL;
38     
View Code

 

posted @ 2015-02-22 15:48  stezqy  阅读(144)  评论(0)    收藏  举报