《算法导论》第十章----基本数据结构

《算法导论》学习记录目录

基本的数据结构是很基础的东西,而且运行时间也很容易看出来,所以本文也是简单地提及一些性质,主要还是通过一些练习来熟悉它们的性质。

(PS:无聊翻开TAOCP的第一卷,发现第二章也是讲一些数据结构,而且讲得很详细。如果明年年初计划可以完成,就应该开始看TAOCP,继续努力吧!)

栈是先进后出(后进先出),就好像洗盘子的时候,你最先放的盘子在最底,下次拿出来洗,就是最后才拿出来。(例子举得有点搓。。。)

具体操作为进栈、出栈(也叫压入、弹出)。

因为是基于数组来实现栈,所以不仅仅要注意下溢(空栈出栈),还要注意上溢(满栈进栈)。

 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-2

说明如何用一个数组A[1..n]来实现两个栈,使得两个栈中的元素总数不到n时,两者都不会发生上溢。注意PUSH和POP操作的时间应为O(1)

分别将数组的头和尾作为单独的两个栈。见代码。

 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:还有一些练习没完成。。完成会不定期更新。。。。

还要继续努力,朝着目标进发!!!

posted @ 2013-10-20 11:49  alan_forever  阅读(2435)  评论(4编辑  收藏  举报