《算法導論》第十章----基本數據結構

《算法導論》學習記錄目錄html

基本的數據結構是很基礎的東西,並且運行時間也很容易看出來,因此本文也是簡單地說起一些性質,主要仍是經過一些練習來熟悉它們的性質。前端

(PS:無聊翻開TAOCP的第一卷,發現第二章也是講一些數據結構,並且講得很詳細。若是明年年初計劃能夠完成,就應該開始看TAOCP,繼續努力吧!)算法

數組

棧是先進後出(後進先出),就好像洗盤子的時候,你最早放的盤子在最底,下次拿出來洗,就是最後纔拿出來。(例子舉得有點搓。。。)數據結構

具體操做爲進棧、出棧(也叫壓入、彈出)。ide

由於是基於數組來實現棧,因此不單單要注意下溢(空棧出棧),還要注意上溢(滿棧進棧)。學習

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define MAX 6
 5 
 6 typedef struct {
 7     int array[MAX];
 8     int top;
 9 }Stack;                             //棧結構體,包含數組和棧頂下標的記錄。
10 
11 int stack_empty(Stack *S);          //判斷是否爲空棧
12 
13 void push(Stack *S, int x);         //進棧操做
14 
15 int pop(Stack *S);                  //出棧操做
16 
17 int main(){
18     Stack *S;
19     S->top = -1;
20     //stack_empty(S);
21     pop(S);
22     int i, num;
23     for(i = 0; i <= 5; i++){
24         scanf("%d", &num);
25         push(S, num);
26     }
27 
28     int p = pop(S);
29     printf("%d\n", p);
30 
31     return 0;
32 }
33 
34 /*
35  * 棧頂初始爲-1,判斷是否爲-1
36  */
37 int stack_empty(Stack *S){
38     if(S->top == -1)
39         return 1;
40     else
41         return 0;
42 }
43 
44 /*
45  * 進棧操做,若是棧頂的下標恰好爲數組的結尾,就提示上溢,不能再進棧
46  */
47 void push(Stack *S, int x){
48     if(S->top+1 == MAX){
49         printf("overflow\n");
50         return ;
51     }
52     else{
53         S->top++;
54         S->array[S->top] = x;
55     }
56 }
57 
58 /*
59  * 出棧操做,若是棧爲空,提示下溢,不能出棧
60  */
61 int pop(Stack *S){
62     if(stack_empty(S)){
63         printf("underflow\n");
64         return ;
65     }
66     else{
67         //S->top--;
68         return S->array[S->top--];
69     }
70 }
View Code

練習10.1-2spa

說明如何用一個數組A[1..n]來實現兩個棧,使得兩個棧中的元素總數不到n時,二者都不會發生上溢。注意PUSH和POP操做的時間應爲O(1)3d

分別將數組的頭和尾做爲單獨的兩個棧。見代碼。指針

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define MAX 12
 5 
 6 typedef struct {
 7     int array[MAX];
 8     int top_1;
 9     int top_2;
10     //int which;
11 }T_Stack;                                   //棧結構,一個數組,兩個棧頂下標(一頭一尾)
12 
13 int empty(T_Stack *T_S, int which);         //判斷棧是否爲空,which爲1對應數組頭的那個棧,which爲2對應數組尾的那個棧
14 
15 void push(T_Stack *T_S, int which, int x);  //進棧操做
16 
17 int pop(T_Stack *T_S, int which);           //出棧操做
18 
19 int main(){
20     int i, num;
21     T_Stack *T_S;
22     T_S->top_1 = -1;
23     T_S->top_2 = MAX;
24     
25     for(i = 1; i <= 6; i++){
26         scanf("%d", &num);
27         push(T_S, 1, num);
28     }
29 
30     for(i = 1; i <= 6; i++){
31         scanf("%d", &num);
32         push(T_S, 2, num);
33     }
34 
35     int po = pop(T_S, 1);
36     printf("%d\n", po);
37 
38     po = pop(T_S, 2);
39     printf("%d\n", po);
40 
41 
42     return 0;
43 }
44 
45 int empty(T_Stack *T_S, int which){
46     if(which == 1){
47         if(T_S->top_1 == -1)
48             return 1;
49         else
50             return 0;
51     }
52 
53     else if(which == 2){
54         if(T_S->top_2 == MAX)
55             return 1;
56         else
57             return 0;
58     }
59 }
60 
61 void push(T_Stack *T_S, int which, int x){
62     if(T_S->top_1 + 1 == T_S->top_2){
63         printf("overflow\n");
64         return ;
65     }
66 
67     if(which == 1){
68         T_S->top_1++;
69         T_S->array[T_S->top_1] = x;
70     }
71     else if(which == 2){
72         T_S->top_2--;
73         T_S->array[T_S->top_2] = x;
74     }
75 }
76 
77 int pop(T_Stack *T_S, int which){
78     if(which == 1){
79         if(empty(T_S, which)){
80             printf("underflow\n");
81             return ;
82         }
83         else{
84             //T_S->top1--;
85             return T_S->array[T_S->top_1--];
86         }
87     }
88     else if(which == 2){
89         if(empty(T_S, which)){
90             printf("underflow\n");
91             return ;
92         }
93         else{
94             //T_S->top2++;
95             return T_S->array[T_S->top_2++];
96         }
97     }
98 }
View Code

隊列

隊列是先進先出,就和排隊同樣,排頭的比排尾的先。

具體操做爲入隊、出隊。

一樣是由於基於數組來實現(循環數組),因此要注意下溢(隊列爲空,再出隊)和上溢(隊列爲滿,再入隊)。(PS:代碼已添加處理上下溢問題,練習10.1-4)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define MAX 7
 5 
 6 typedef struct {
 7     int array[MAX];
 8     int head;
 9     int tail;
10 }Queue;                             //隊列結構體,一個數組,一個隊首下標,一個隊尾下標
11 
12 void enqueue(Queue *Q, int x);      //進隊列
13 
14 int dequeue(Queue *Q);              //出隊列
15 
16 int main(){
17     int i, num;
18     Queue *Q;
19     Q->head = Q->tail = 0;
20     dequeue(Q);
21     for(i = 1; i <= 6; i++){
22         scanf("%d", &num);
23         enqueue(Q, num);
24     }
25 
26     for(i = 1; i <= 6; i++){
27         int de = dequeue(Q);
28         printf("%d\n", de);
29     }
30     if(Q->head == Q->tail)
31         printf("Yes\n");
32     return 0;
33 }
34 
35 /*
36  * 若是隊首下標等於隊尾下標+1,表示上溢,不能再進隊列。
37  * 若是隊尾下標在添加元素後等於數組的末端,那麼就要回到數組的前端(前提未上溢)
38  */
39 void enqueue(Queue *Q, int x){
40     if(Q->head == ((Q->tail + 1) % MAX)){
41         printf("overflow\n");
42         return ;
43     }
44 
45     else{
46         Q->array[Q->tail] = x;
47         Q->tail = (Q->tail + 1) % MAX;
48     }
49 }
50 
51 /*
52  * 若是隊首下標等於隊尾下標,表示隊列爲空,不能出隊列
53  * 若是隊首小表在出隊列後等於數組末端,那麼就要回到數組的前端
54  */
55 int dequeue(Queue *Q){
56     if(Q->head == Q->tail){
57         printf("underflow\n");
58         return ;
59     }
60     int x = Q->array[Q->head];
61     if(Q->head == MAX-1)
62         Q->head = 0;
63     else
64         Q->head++;
65 
66     return x;
67 }
View Code

練習10.1-5

棧的插入和刪除都在同一端進行,而隊列的插入和刪除卻在兩頭進行。另有一種雙端隊列,其兩端均可以左插入和刪除操做。對於一個用數組構造的雙端隊列,請寫出四個在兩端進行插入和刪除操做的過程,要求運行時間都爲O(1)

PS:已添加處理上下溢問題

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define MAX 15
 5 
 6 typedef struct {
 7     int array[MAX];
 8     int head;
 9     int tail;
10 }Deque;                             //雙端隊列結構體,一個數組、一個頭下標、一個尾下標
11 
12 void H_enqueue(Deque *D, int x);    //從隊列頭進隊列
13 
14 int H_dequeue(Deque *D);            //從隊列頭出隊列
15 
16 void T_enqueue(Deque *D, int x);    //從隊列尾進隊列
17 
18 int T_dequeue(Deque *D);            //從隊列尾出隊列
19 
20 int main(){
21     int i, num;
22     Deque *de;
23     de->head = de->tail = 0;
24     H_dequeue(de);
25     T_dequeue(de);
26     for(i = 1; i <= 7; i++){
27         scanf("%d", &num);
28         H_enqueue(de, num);
29     }
30     for(i = 1; i <= 7; i++){
31         scanf("%d", &num);
32         T_enqueue(de, num);
33     }
34     int H_de = H_dequeue(de);
35     int T_de = T_dequeue(de);
36     printf("%d\n", H_de);
37     printf("%d\n", T_de);
38 
39     return 0;
40 }
41 
42 void H_enqueue(Deque *D, int x){
43     if(D->head == ((D->tail + 1) % MAX)){
44         printf("overflow\n");
45         return ;
46     }
47 
48     else{
49         if(D->head == 0)
50             D->head = MAX-1;  
51         else
52             D->head--;
53         D->array[D->head] = x;
54     }
55 }
56 
57 int H_dequeue(Deque *D){
58     if(D->head == D->tail){
59         printf("underflow\n");
60         return ;
61     }
62     int x = D->array[D->head];
63     if(D->head == MAX-1)
64         D->head = 0;
65     else
66         D->head++;
67 
68     return x;
69 }
70 
71 void T_enqueue(Deque *D, int x){
72     if(D->head == ((D->tail + 1) % MAX)){
73         printf("overflow\n");
74         return ;
75     }
76 
77     else{
78         D->array[D->tail] = x;
79         D->tail = (D->tail + 1) % MAX;
80     }
81 }
82 
83 int T_dequeue(Deque *D){
84     if(D->head == D->tail){
85         printf("underflow\n");
86         return ;
87     }
88 
89     int x = D->array[D->tail-1];
90     if(D->tail == 0)
91         D->tail = MAX-1;
92     else
93         D->tail--;
94     
95     return x;
96 }
View Code

練習10.1-6

說明如何用兩個棧實現一個隊列,並分析有關隊列操做的運行時間

一個棧爲A、一個棧爲B。入隊列的時候至關於進B棧,若是B棧已經爲滿棧的時候,將B棧的全部元素出棧,再進A棧,而後把要入隊列的元素進B棧。若是A、B棧同爲滿棧的時候,爲上溢。出隊列時就從A棧彈出(若是A棧爲空,先從B棧依次彈出並一次進A棧)。PS:代碼可能有瑕疵。。。。

#include <stdio.h>

#define MAX 4

typedef struct {
    int array[MAX];
    int top;
}Stack;

typedef struct {
    Stack pr_stack;
    Stack ne_stack;
}Queue;

int stack_empty(Stack *S);

int push(Stack *S, int x);

int pop(Stack *S);

void enqueue(Queue *Q, int x);

int dequeue(Queue *Q);

int main(){
    int i, num;
    Queue *Q;
    Stack Sp;
    Sp.top = -1;
    Stack Sn;
    Sn.top = -1;
    Q->pr_stack = Sp;
    Q->ne_stack = Sn;
    
    dequeue(Q);
    for(i = 1; i <= 8; i++){
        scanf("%d", &num);
        enqueue(Q, num);
    }
    enqueue(Q, num+1);

    int de;
    for(i = 1; i <= 8; i++){
        de = dequeue(Q);
        printf("%d ", de);
    }
    printf("\n");
    return 0;
}

int stack_empty(Stack *S){
    if(S->top == -1)
        return 1;
    else
        return 0;
}

int push(Stack *S, int x){
    if(S->top+1 == MAX){
        return 0;
    }
    else{
        S->top++;
        S->array[S->top] = x;
        return 1;
    }
}

int pop(Stack *S){
    if(stack_empty(S)){
        printf("underflow\n");
        return ;
    }
    else{
        return S->array[S->top--];
    }
}

void enqueue(Queue *Q, int x){
    if(push(&Q->ne_stack, x) == 0){
        if(Q->pr_stack.top+1 == MAX){
            printf("overflow\n");
            return ;
        }
        else{
            while(Q->pr_stack.top+1 != MAX && !(stack_empty(&Q->ne_stack))){
                push(&Q->pr_stack, pop(&Q->ne_stack));
            }
            push(&Q->ne_stack, x);
        }
    }
}

int dequeue(Queue *Q){
    if(stack_empty(&Q->pr_stack)){
        if(stack_empty(&Q->ne_stack)){
            printf("underflow\n");
            return ;
        }

        while(Q->pr_stack.top+1 != MAX && !(stack_empty(&Q->ne_stack))){
            push(&Q->pr_stack, pop(&Q->ne_stack));
        }
    }
    return pop(&Q->pr_stack);
}
View Code

鏈表

鏈表中的對象按照線性順序排序,不像數組經過下標來決定對象的線性序,鏈表的順序是由對象的指針來決定的。

PS:下列爲單鏈表實現代碼(頭插入),注意要釋放刪除結點的內存。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct ListNode{
 5     int value;
 6     struct ListNode * next;
 7 }ListNode;                          //鏈表結點結構體,對象的值,後指針
 8 
 9 void list_insert(ListNode *l , int x);  //鏈表的插入,頭插入
10 
11 void print_list(ListNode *l);           //打印鏈表
12 
13 int list_search(ListNode *l, int k);    //鏈表的查找,k爲要查找的值
14 
15 void list_delete(ListNode *l, int k);   //鏈表的刪除,k爲要刪除的結點的值
16 
17 int main(){
18     ListNode *head;                         //頭節點
19     int i, num;
20     head = (ListNode *)malloc(sizeof(ListNode));
21     head->next = NULL;
22 
23     for(i = 1; i <= 5; i++){
24         scanf("%d", &num);
25         list_insert(head, num);
26     }
27 
28     print_list(head);
29 
30     printf("%d\n", list_search(head, 3));
31 
32     list_delete(head, 5);
33     print_list(head);
34     return 0;
35 }
36 
37 void list_insert(ListNode *l, int x){
38     ListNode * p;
39     p = (ListNode *)malloc(sizeof(ListNode));
40     p->value = x;
41     if(l->next == NULL){
42         l->next = p;
43         p->next = NULL;
44     }
45     else{
46         p->next = l->next;
47         l->next = p;
48     }
49     
50 }
51 
52 void print_list(ListNode *l){
53     ListNode * p = l->next;
54     while(p != NULL){
55         printf("%d ", p->value);
56         p = p->next;
57     }
58     printf("\n");
59 }
60 
61 int list_search(ListNode *l, int key){
62     ListNode *p = l->next;
63     while(p != NULL){
64         if(p->value == key)
65             return 1;
66         p = p->next;
67     }
68 
69     return 0;
70 }
71 
72 void list_delete(ListNode *l, int key){
73     ListNode *p = l->next;
74 
75     if(p->value == key){
76         l->next = p->next;
77         free(p);
78     }
79     else{
80         while(p->next->value != key){
81             p = p->next;
82         }
83         ListNode *de = p->next;
84         p->next = p->next->next;
85         free(de);               //要釋放刪除節點的內存
86     }
87 }
View Code

PS:下列爲雙鏈表代碼實現(頭插入)。(註釋參考單鏈表。。。)(添加日期:2013.10.27)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct ListNode {
 5     int value;
 6     struct ListNode * next;
 7     struct ListNode * prev;
 8 }ListNode;
 9 
10 void list_insert(ListNode *l, int x);
11 
12 void print_list(ListNode *l);
13 
14 int list_search(ListNode *l, int k);
15 
16 void list_delete(ListNode *l, int k);
17 
18 int main(){
19     int i, num;
20     ListNode *head;
21     head = (ListNode *)malloc(sizeof(ListNode));
22     head->next = NULL;
23 
24     for(i = 1; i <= 5; i++){
25         scanf("%d", &num);
26         list_insert(head, num);
27     }
28     //print_list(head);
29     list_delete(head, 3);
30     print_list(head);
31     return 0;
32 }
33 
34 void list_insert(ListNode *l, int x){
35     ListNode * n;
36     n = (ListNode *)malloc(sizeof(ListNode));
37     n->value = x;
38 
39     if(l->next == NULL){
40         l->next = n;
41         n->prev = l;
42         n->next = NULL;
43     }
44 
45     else{
46         n->next = l->next;
47         l->next->prev = n;
48         l->next = n;
49         n->prev = l;
50     }
51 }
52 
53 void print_list(ListNode *l){
54     ListNode *p = l->next;
55 
56     while(p != NULL){
57         printf("%d ", p->value);
58         p = p->next;
59     }
60 
61     printf("\n");
62 }
63 
64 int list_search(ListNode *l, int k){
65     ListNode *p = l->next;
66 
67     while(p != NULL){
68         if(p->value == k){
69             return 1;
70         }
71         p = p->next;
72     }
73 
74     return 0;
75 }
76 
77 void list_delete(ListNode *l, int k){
78     ListNode *p = l->next;
79     while(p != NULL){
80         if(p->value == k){
81             p->prev->next = p->next;
82             p->next->prev = p->prev;
83 
84             free(p);
85         }
86         p = p->next;
87     }
88 }
View Code

練習10.2-2

用一單鏈表L實現一個棧,要求PUSH和POP操做的時間仍爲O(1)

該單鏈表的插入爲頭插入,對應PUSH操做,POP操做爲刪除頭結點指向的下一結點。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct ListNode{
 5     int value;
 6     struct ListNode * next;
 7 }ListNode;
 8 
 9 typedef struct {
10     ListNode * top;
11 }Stack;
12 
13 void list_insert(ListNode *l , int x);
14 
15 void print_list(ListNode *l);
16 
17 int stack_empty(Stack *S);
18 
19 void push(Stack *S, int x);
20 
21 int pop(Stack *S);
22 
23 int main(){
24     int i, num;
25     Stack * S;
26     S = (Stack *)malloc(sizeof(Stack));
27     S->top = (ListNode *)malloc(sizeof(ListNode));
28 
29     for(i = 1; i <= 5; i++){
30         scanf("%d", &num);
31         push(S, num);
32     }
33 
34     //printf("%d\n", stack_empty(S));
35     //print_list(S->top);
36 
37     for(i = 1; i<= 5; i++)
38         printf("%d ", pop(S));
39     printf("\n");
40 
41     return 0;
42 }
43 
44 void list_insert(ListNode *l, int x){
45     ListNode * p;
46     p = (ListNode *)malloc(sizeof(ListNode));
47     p->value = x;
48     if(l->next == NULL){
49         l->next = p;
50         p->next = NULL;
51     }
52     else{
53         p->next = l->next;
54     }
55     l->next = p;
56 }
57 
58 void print_list(ListNode *l){
59     ListNode * p = l->next;
60     while(p != NULL){
61         printf("%d ", p->value);
62         p = p->next;
63     }
64     printf("\n");
65 }
66 
67 
68 int stack_empty(Stack *S){
69     if(S->top->next == NULL)
70         return 1;
71     else
72         return 0;
73 }
74 
75 void push(Stack *S, int x){
76     list_insert(S->top, x);
77 }
78 
79 int pop(Stack *S){
80     if(stack_empty(S)){
81         printf("underflow\n");
82         return ;
83     }
84     else{
85         ListNode *p = S->top->next;
86         int x = p->value;
87         S->top->next = p->next;
88         free(p);
89         return x;
90     }
91 }
View Code

 

PS:還有一些練習沒完成。。完成會不按期更新。。。。

還要繼續努力,朝着目標進發!!!

相關文章
相關標籤/搜索