主要是考完期中之后发现自己一些基础的东西(特指链表)太差了,所以去学了一下,现在把它挂上来,方便以后回忆

链表补救计划

1.malloc

malloc函数引用前需要#include
malloc函数的返回类型是void*,如果没有空间即返回失败,则返回0, 或者是NULL
free()把申请的空间还给系统,申请过的空间,最终都要还, 且只能还申请的空间的首地址,即申请的是什么就只能free()什么,容易出现的问题:

  • free后又free了一次
  • free的地址变了,即可能内存申请的时候用的是p,然后在程序执行时出现了p++,再去free时就会出现问题,建议先将p改为原来的值再去free

一个程序的例子: (输入一个数number,然后再连续输入number个数)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. int main()
  4. {
  5. int number, i;
  6. scanf("%d", &number);
  7. // for C99 and after
  8. // int a[number];
  9. // for malloc
  10. int *a;
  11. // 注意这里的sizeof后面是int
  12. a = (int*)malloc(number*sizeof(int));
  13. for (i=0; i<number; i++)
  14. scanf("%d", &a[i]);
  15. for (i=0; i<number; i++)
  16. printf("%d", a[i]);
  17. free(a);
  18. return 0;
  19. }

2.linked list

一个程序的例子:(输入n个数,n未知,以-1结尾,再输出)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. typedef struct _node{
  4. int value;
  5. struct _node* next;
  6. }node;
  7. int main()
  8. {
  9. node *head = NULL;
  10. int number;
  11. do{
  12. scanf("%d", &number);
  13. if (number == -1)
  14. break;
  15. node *p = (node*)malloc(sizeof(node)); //注意这里是sizeof(node)而不是sizeof(node*)
  16. p->value = number;
  17. p->next = NULL;
  18. if (head) //加这一步是为了确定head非空
  19. {
  20. node *tail = head;
  21. while (tail->next)
  22. tail = tail->next;
  23. tail->next = p;
  24. }
  25. else
  26. head = p;
  27. }while(1);
  28. node *q = head;
  29. for(; q; q=q->next)
  30. {
  31. printf("%d", q->value);
  32. }
  33. return 0;
  34. }

3.linked list 函数

这里同样也是上一个的例子

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. typedef struct _node{
  4. int value;
  5. struct _node* next;
  6. }node;
  7. typedef struct _list{
  8. node* head;
  9. }List;
  10. void build_linkedlist(List *plist);
  11. int main()
  12. {
  13. List list;
  14. list.head = NULL;
  15. int number;
  16. build_linkedlist(&list); //传进去的是list的地址
  17. node *q = list.head;
  18. for(; q; q=q->next)
  19. {
  20. printf("%d", q->value);
  21. }
  22. return 0;
  23. }
  24. void build_linkedlist(List *plist)
  25. {
  26. int number;
  27. do{
  28. scanf("%d", &number);
  29. if (number == -1)
  30. break;
  31. node *p = (node*)malloc(sizeof(node)); //注意这里是sizeof(node)而不是sizeof(node*)
  32. p->value = number;
  33. p->next = NULL;
  34. if ((*plist).head) //加这一步是为了确定head非空
  35. {
  36. node *tail = (*plist).head; //(*plist).head相当于plist->head
  37. while (tail->next)
  38. tail = tail->next;
  39. tail->next = p;
  40. }
  41. else
  42. (*plist).head = p;
  43. }while(1);
  44. return ;
  45. }

这里是通过建立了一个函数来对链表进行操作,建立结构体List的原因是方便对链表进行管理,成体系。
我们在向函数中传参数的时候传入的是list的地址,因为我们想对head这个指针做修改,即对一个东西的地址做修改,所以我们需要传入的是地址的地址,这样才能完成对其的修改。

4.其他一些要注意的地方

如果一个指针出现在了箭头的左边例p->value中的p,我们一定在程序中要直接或间接地判断p会不会是NULL
这点非常非常重要。
一般我们很有可能会没有考虑空链表的情况
image.png
例如,在上述代码中,p和q都出现在了箭头地左边,但p是被判断过地,因为在for循环地进入条件就是p即p!=NULL,而q是没有判断过的,所以为避免错误,这里应该补充对q的判断看其是不是NULL 这一点非常非常重要

删掉链表的结点时首先让其上一个结点的结点指向其下一个结点,再free掉该结点即可

删除链表

  1. for (p=head; p; p=q)
  2. {
  3. q = p->next;
  4. free(p);
  5. }

因为结束时p和q都是NULL所以就free完毕了

做题时遇到的问题

段错误

  1. Polynomial Add( Polynomial a, Polynomial b )
  2. {
  3. if (a == NULL)
  4. return b;
  5. else if (b == NULL)
  6. return a;
  7. else
  8. {
  9. Polynomial head, tail;
  10. tail = (Polynomial)malloc(sizeof(struct Node));
  11. //这里如果让不对tail做初始化也会段错误,好像是因为一定要对指针做初始化,tail地初始化是malloc来的,而head的初始化是tail来的
  12. head = tail;
  13. //这里如果写head = tail = NULL;会段错误,好像是因为如果让其为NULL,它就没有Next了,所以会段错误
  14. a = a->Next;
  15. b = b->Next;
  16. while (a&&b)
  17. {
  18. Polynomial this = (Polynomial)malloc(sizeof(struct Node));
  19. if (a->Exponent > b->Exponent)
  20. {
  21. this->Exponent = a->Exponent;
  22. this->Coefficient = a->Coefficient;
  23. a = a->Next;
  24. }
  25. else if(a->Exponent < b->Exponent)
  26. {
  27. this->Exponent = b->Exponent;
  28. this->Coefficient = b->Coefficient;
  29. b = b->Next;
  30. }
  31. else
  32. {
  33. this->Exponent = b->Exponent;
  34. this->Coefficient = b->Coefficient + a->Coefficient;
  35. a = a->Next;
  36. b = b->Next;
  37. if (this->Coefficient == 0)
  38. continue;
  39. }
  40. tail->Next = this;
  41. tail = this;
  42. }
  43. if (a)
  44. tail->Next = a;
  45. if (b)
  46. tail->Next = b;
  47. return head;
  48. }
  49. }

对于以上的代码,下面的写法也是可以通过的

  1. Polynomial Add( Polynomial a, Polynomial b )
  2. {
  3. if (a->Next == NULL)
  4. return b;
  5. else if (b->Next == NULL)
  6. return a;
  7. else
  8. {
  9. Polynomial head, tail;
  10. head = tail = NULL;//这里让head和tail直接为NULL
  11. a = a->Next;
  12. b = b->Next;
  13. while (a&&b)
  14. {
  15. Polynomial this = (Polynomial)malloc(sizeof(struct Node));
  16. if (a->Exponent > b->Exponent)
  17. {
  18. this->Exponent = a->Exponent;
  19. this->Coefficient = a->Coefficient;
  20. a = a->Next;
  21. }
  22. else if(a->Exponent < b->Exponent)
  23. {
  24. this->Exponent = b->Exponent;
  25. this->Coefficient = b->Coefficient;
  26. b = b->Next;
  27. }
  28. else
  29. {
  30. this->Exponent = b->Exponent;
  31. this->Coefficient = b->Coefficient + a->Coefficient;
  32. a = a->Next;
  33. b = b->Next;
  34. if (this->Coefficient == 0)
  35. continue;
  36. }
  37. if (head == NULL)
  38. head = this;//在第一次经过时,这里和下面分布重新对tail和head做了初始化
  39. else
  40. tail->Next = this;
  41. tail = this;//
  42. }
  43. if (a)
  44. tail->Next = a;
  45. if (b)
  46. tail->Next = b;
  47. Polynomial head1 = (Polynomial)malloc(sizeof(struct Node));
  48. head1->Next = head;
  49. return head1;//head1的作用是为了加一个dummy head
  50. }
  51. }

而对没有dummy head的情况我们用下面的代码

  1. head = tail = NULL;
  2. ...
  3. ...
  4. if (head == NULL)
  5. head = cur;
  6. else
  7. tail->next = cur;
  8. tail=cur;

但一般都是会有dummy head的,所以,嗯

给定一个有dummy head的链表,要求返回一个逆序的链表,且给定的链表也要是逆序的 (Data Structures and Algorithms (English) 6-4)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef int ElementType;
  4. typedef struct Node *PtrToNode;
  5. typedef PtrToNode List;
  6. typedef PtrToNode Position;
  7. struct Node {
  8. ElementType Element;
  9. Position Next;
  10. };
  11. List Read(); /* details omitted */
  12. void Print( List L ); /* details omitted */
  13. List Reverse( List L );
  14. int main()
  15. {
  16. List L1, L2;
  17. L1 = Read();
  18. L2 = Reverse(L1);
  19. Print(L1);
  20. Print(L2);
  21. return 0;
  22. }
  23. /* Your function will be put here */
  24. List Reverse( List L )
  25. {
  26. if (L->Next==NULL || L->Next->Next==NULL)
  27. return L;
  28. List l1, pre, l2;
  29. l1 = L->Next->Next;
  30. l2 = L->Next;
  31. l2->Next = NULL;
  32. /*
  33. 这里的上面三行我本来写成了
  34. {
  35. l1 = L->Next;
  36. l2 = L->Next;
  37. l2->Next = NULL;
  38. l1 = l1->Next;
  39. }
  40. 但这样写是错的,因为我们不难看到在
  41. l1 = L->Next;
  42. l2 = L->Next;
  43. 的赋值之后,l1和l2指向了同一块地方,而下一行的l2->Next = NULL;又对这一块地方做了修改,这就会使l1->Next也为NULL。
  44. */
  45. while (l1)
  46. {
  47. pre = l1->Next;
  48. l1->Next = l2;
  49. l2 = l1;
  50. l1 = pre;
  51. }
  52. L->Next = l2;
  53. return L;
  54. }

如果要使给定的链表也是逆序的就要让return 参数,即L
image.png
如上图所示,一个有dummy head的linked list,即L是一块地址,它指向一块地址,而这块地址的Next也是一块地址,指向链表的第一个结点,那么,我们往一个函数里传入L相当于传入了地址的地址,即在一个函数里,虽然主函数里的L和被调函数的L是位于不同的两个地址的两个相同的值,但正因为他们相同,都指向上图中中间这个结点,如果如果我们把这个结点的next修改一下,就可以改变原主函数中L所指向的值

Tree

做到的一些题

判断两个树是否同构

  1. int Isomorphic( Tree T1, Tree T2 )
  2. {
  3. if (T1->Element == T2->Element)
  4. {
  5. if (!T1->Left && !T1->Right && !T2->Left && !T2->Right)
  6. return 1;
  7. else if (!T1->Left && !T2->Left && T1->Right && T2->Right)
  8. ...
  9. }
  10. else
  11. return 0;
  12. }

不要像上面这么写,这么写的话会写很多,而且容易漏掉一些情况,要写成下面这种

  1. int Isomorphic( Tree T1, Tree T2 )
  2. {
  3. if (T1 == NULL && T2 == NULL)
  4. return 1;
  5. else if (T1 != NULL && T2 == NULL)
  6. return 0;
  7. else if (T1 == NULL && T2 != NULL)
  8. return 0;
  9. else if (T1 != NULL && T2 != NULL)
  10. {
  11. if (T1 -> Element != T2 -> Element)
  12. return 0;
  13. else
  14. return ((Isomorphic(T1 -> Left, T2 -> Right) && Isomorphic(T1 -> Right, T2 -> Left)) || (Isomorphic(T1 -> Right, T2 -> Right) && Isomorphic(T1 -> Left, T2 -> Left)));
  15. }
  16. }

即传入的T1和T2可以是NULL然后让这个函数对是不是NULL来判断,这样写的话可以省好多位置

求二叉树的高度

用一个简单的递归即可

  1. int countheight(BinTree T)
  2. {
  3. if (T==NULL)
  4. return 0;
  5. else if (countheight(T->Left) > countheight(T->Right))
  6. return countheight(T->Left) + 1;
  7. else
  8. return countheight(T->Right) + 1;
  9. }