Data structure advanced training course notes and algorithm exercises
数据结构进阶实训课程笔记和算法练习
Source Code: https://github.com/MysticalGuest/DataStructure/tree/master/AdvancedJuniorTraining
题目1
1
| 给定一个单链表L,L为头指针,判断该链表内是否局部存在环?
|
1.1 算法设计思想
使用快慢指针判断单链表是否存在环。
使用slow、fast 2个指针,slow慢指针每次向前走1步,fast快指针每次向前走2步,若存在环的话,必定存在某个时候 slow = fast 快慢指针相遇。
返回值为1:存在环
返回值为0:不存在环
1.2 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| typedef struct Node { int data; struct Node *next; }Node, *LinkList;
void InitLinkList(LinkList *L) { *L = (LinkList)malloc(sizeof(Node)); (*L)->next = NULL; Node *r=*L, *s, *temp; int i=0; while(i<10){ s=(Node*)malloc(sizeof(Node)); s->data=i; r->next=s; s->next=NULL; if(i==4){ temp=r; } r=s; i++; } r->next=temp; }
int IsLoopLinkList(LinkList list){ if(list == NULL){ return 0; } if(list->next == NULL){ return 0; } Node* slow = list; Node* fast = list; int loc = 0; while (1){ if(fast->next == NULL){ return 0; } else{ if (fast->next != NULL && fast->next->next != NULL){ fast = fast->next->next; slow = slow->next; } else{ fast = fast->next; } } if(slow == fast){ return 1; } } return 0; }
|
1.3 运行情况截图
题目2
1 2 3 4
| 找到单链表中倒数第k个结点。找出解决方法 要求:尽可能高效 例如:一个链表有6个结点,(1,2,3,4,5,6) 这个链表的倒数第3个结点是:值为4的结点
|
2.1 算法设计思想
先遍历获得链表长度listlen(L)
;
然后计算得出倒数第k个节点的正数位置,也就是listlen(L)-k+1
;
遍历到listlen(L)-k+1
的节点,然后输出
2.2 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int listlen(LinkList L){ int len=0; Node *head=L; while(head->next!=NULL){ len++; head=head->next; } return len; }
scanf("%d", &k); for(i=0; i<listlen(L)-k+1; i++){ p=p->next; }
|
2.3 运行情况截图
题目3
1 2
| 在O(1)时间删除单链表结点; 给定单链表L及其中一个结点地址p,定义一个函数实现在O(1)时间删除该结点。
|
3.1 算法设计思想
将节点p的下一个节点的值赋给p;
p的后继指向p的后继的后继;
然后free掉p的后继
3.2 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void InitLinkList(LinkList *L, LinkList *temp) { *L = (LinkList)malloc(sizeof(Node)); (*L)->next = NULL; Node *r=*L, *s; int i=0; while(i<10){ s=(Node*)malloc(sizeof(Node)); s->data=i; r->next=s; s->next=NULL; if(i==5){ *temp=r; } r=s; i++; } }
InitLinkList(&L, &p);
s=p->next; p->data = s->data; p->next=s->next; free(s);
|
3.3 运行情况截图
题目4
1 2 3
| 假定用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,例如:loading和being。 - 设计一个高效的算法,找出str1和str2的共同后缀的起始位置。(可能有也可能没有。) - 分析算法的时空效率
|
4.1 算法设计思想
分别获得链表str1和str2的长度;
移动长度较长的链表的头指针,使得两指针的起始位置相同;
然后同时往后移动,遇到相同地址的节点即为共同后缀的起始位置
4.2 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| LinkList reverse(LinkList L){ if(L->next == NULL || L->next->next == NULL) { return L; } Node *r, *p = L->next, *q = L->next->next; while(q != NULL){ r = q->next; q->next = p; p = q; q = r; }
L->next->next = NULL; L->next = p; return L; }
LinkList commonSuffix1(LinkList L1, LinkList L2){ Node *p, *q; int len1, len2; len1=listlen(L1); len2=listlen(L2); if(lastNode(L1) != lastNode(L2)){ return NULL; } else{ for(p=L1; len1>len2; len1--){ p=p->next; } for(q=L2; len2>len1; len2--){ q=q->next; } while(p->next != NULL && p->next != q->next){ p=p->next; q=q->next; } return p->next; } }
LinkList commonSuffix2(LinkList L1, LinkList L2){ Node *p=L1, *q=L2; if(L1->next == NULL || L2->next == NULL){ return NULL; } else{ while(p->next != NULL && q->next != NULL && p->next != q->next){ p=p->next; q=q->next; } return p->next; } }
|
4.3 运行情况截图