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

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

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

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

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

你可能感兴趣的:(数据结构)