《算法導論》學習記錄目錄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 }
練習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 }
隊列
隊列是先進先出,就和排隊同樣,排頭的比排尾的先。
具體操做爲入隊、出隊。
一樣是由於基於數組來實現(循環數組),因此要注意下溢(隊列爲空,再出隊)和上溢(隊列爲滿,再入隊)。(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 }
練習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 }
練習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); }
鏈表
鏈表中的對象按照線性順序排序,不像數組經過下標來決定對象的線性序,鏈表的順序是由對象的指針來決定的。
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 }
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 }
練習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 }
PS:還有一些練習沒完成。。完成會不按期更新。。。。
還要繼續努力,朝着目標進發!!!