最近参加面试遇到的一些常见的单链表题目,总结思路和实现代码。
1.单链表的反序
2.给单链表建环
3.检测单链表是否有环
4.给单链表解环
5.检测两条链表是否相交
6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)
7.合并两个有序链表
1.单链表的反序
01 | //逆转链表,并返回逆转后的头节点 |
02 | node* reverse(node *head) |
03 | { |
04 | if (head == NULL || head->next == NULL) |
05 | { |
06 | return head; |
07 | } |
08 | node *cur = head; |
09 | node *pre = NULL; |
10 | node *tmp; |
11 | while (cur->next) |
12 | { |
13 | tmp = pre; |
14 | pre = cur; |
15 | cur = cur->next; |
16 | pre->next = tmp; //操作pre的next逆转 |
17 | } |
18 | cur->next = pre; //结束时,操作cur的next逆转 |
19 | return cur; |
20 | } |
01 | //方法二 |
02 | node *reverse(node *head) |
03 | { |
04 | node *p, *q, *r; |
05 | |
06 | p = head; |
07 | q = p->next; |
08 | |
09 | while (q != NULL) |
10 | { |
11 | r = q->next; |
12 | q->next = p; |
13 | p = q; |
14 | q = r; |
15 | } |
16 | |
17 | head->next = NULL; |
18 | head = p; |
19 | |
20 | return head; |
21 | } |
2.给单链表建环
01 | //给单链表建环,让尾指针,指向第num个节点,若没有,返回false |
02 | bool bulid_looplink(node *head, int num) |
03 | { |
04 | node *cur = head; |
05 | node *tail = NULL; |
06 | int i = 0; |
07 | if (num <= 0 || head == NULL) |
08 | { |
09 | return false ; |
10 | } |
11 | for (i = 1; i < num; ++i) |
12 | { |
13 | if (cur == NULL) |
14 | { |
15 | return false ; |
16 | } |
17 | cur = cur->next; |
18 | } |
19 | tail = cur; |
20 | while (tail->next) |
21 | { |
22 | tail = tail->next; |
23 | } |
24 | tail->next = cur; |
25 | return true ; |
26 | } |
3.检测单链表是否有环
01 | //检测单链表是否有环,快慢指针 |
02 | bool detect_looplink(node *head) |
03 | { |
04 | node *quick_node = head->next, *slow_node = head; |
05 | if (head == NULL || head->next == NULL) |
06 | { |
07 | return false ; |
08 | } |
09 | while (quick_node != slow_node) |
10 | { |
11 | if (quick_node == NULL || slow_node == NULL) |
12 | break ; |
13 | quick_node = quick_node->next->next; |
14 | slow_node = slow_node->next; |
15 | } |
16 | if (quick_node != NULL && slow_node != NULL) //非尾节点相遇 |
17 | return true ; |
18 | return false ; |
19 | } |
4.给单链表解环
ps:为了增加节点位图的效率,本应使用hash或则红黑树,这里不造车了,直接用 set容器
01 | //找到有环节点,并解环,找到并解环,返回true,无环,返回false |
02 | //思路:先找到环节点:被2个节点指向的节点(一定有环的条件)ps:不考虑中间环,因为只有一个next节点,只可能是尾环 |
03 | bool unloop_link(node *head) |
04 | { |
05 | set<node *> node_bitmap; //node的地址位图 |
06 | unsigned int num = 0; |
07 | node *cur = head, *pre = NULL; |
08 | while (cur != NULL) |
09 | { |
10 | if (!node_bitmap.count(cur) ) //该节点未被遍历过 |
11 | { |
12 | node_bitmap.insert(cur); |
13 | ++num; |
14 | } |
15 | else //指向已被遍历过的节点,此时pre节点为尾节点 |
16 | { |
17 | pre->next = NULL; |
18 | return true ; |
19 | } |
20 | pre = cur; |
21 | cur = cur->next; |
22 | } |
23 | return false ; |
24 | } |
5.检测两条链表是否相交
01 | //检测两条链表是否相交,是则返回第一个交点,否则返回NULL |
02 | //思路:把2个链表各遍历一遍,记下长度length1和length2,若2者的尾节点指针相等,则相交。 |
03 | // 之后再把长的链表从abs(len1-len2)的位置开始遍历,第一个相等的指针为目标节点 |
04 | node* detect_intersect_links(node *first_link, node *second_link) |
05 | { |
06 | int legnth1 = 1, length2 = 1, pos = 0; |
07 | node *cur = NULL, *longer_link = first_link, *shorter_link = second_link; |
08 | if (first_link == NULL || second_link == NULL) |
09 | { |
10 | return NULL; |
11 | } |
12 | while (first_link->next || second_link->next) //遍历2个链表 |
13 | { |
14 | if (first_link->next) |
15 | { |
16 | first_link = first_link->next; |
17 | ++legnth1; |
18 | } |
19 | if (second_link->next) |
20 | { |
21 | second_link = second_link->next; |
22 | ++length2; |
23 | } |
24 | } |
25 | if (first_link != second_link) //比较尾节点 |
26 | { |
27 | return NULL; |
28 | } |
29 | pos = legnth1 - length2; |
30 | if (legnth1 < length2) //保证 longer_link为长链表 |
31 | { |
32 | pos = length2 - legnth1; |
33 | cur = longer_link; |
34 | longer_link = shorter_link; |
35 | shorter_link = cur; |
36 | } |
37 | while (pos-- > 0) |
38 | longer_link = longer_link->next; |
39 | while (longer_link || shorter_link) |
40 | { |
41 | if (longer_link == shorter_link) //找到第一个交点 |
42 | { |
43 | return longer_link; |
44 | } |
45 | longer_link = longer_link->next; |
46 | shorter_link = shorter_link->next; |
47 | } |
48 | return NULL; |
49 | } |
6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)
01 | //无头节点,随机给出单链表中一个非头节点,删除该节点,当传入空节点,或者尾节点时,返回false |
02 | //思路:由于没有头节点,非循环单链表,无法获取目标节点的前节点,所以只能把它的next节点数据前移,并删除next节点 |
03 | //ps:当传入节点为尾节点,无法用此方法删除 |
04 | bool withouthead_delete_node(node *target_node) |
05 | { |
06 | node *cur = NULL; |
07 | if (target_node == NULL || target_node->next == NULL) //空节点或者尾节点,失败 |
08 | { |
09 | return false ; |
10 | } |
11 | cur = target_node->next; |
12 | target_node->name = cur->name; |
13 | target_node->next = cur->next; |
14 | delete cur; |
15 | return true ; |
16 | } |
7.合并两个有序链表
001 | /* |
002 | 递归实现: |
003 | ①算法思想: |
004 | 递归终止条件:若head1为空,返回head2指针(head);若head2为空,返回head1指针(head) |
005 | 递归过程: |
006 | |
007 | 1 若head1->data>head2->data; head 指针应该指向head2所指向的节点,而且head->next应该指向head1和head2->next两个链表的合成序列的头指针; |
008 | |
009 | 2 否则head 指针应该指向head1所指向的节点,而且head->next应该指向head->next和head2两个链表的合成序列的头指针; |
010 | */ |
011 | #include <iostream> |
012 | using namespace std; |
013 | |
014 | /*节点的类定义*/ |
015 | class Node |
016 | { |
017 | public : |
018 | int data; |
019 | Node *next; |
020 | Node( int data) |
021 | { |
022 | this ->data = data; |
023 | } |
024 | }; |
025 | |
026 | /*链表的类定义*/ |
027 | class LinkedList |
028 | { |
029 | public : |
030 | Node *head; |
031 | |
032 | /*用一个整形数组作为参数的构造函数*/ |
033 | LinkedList( int array[]) |
034 | { |
035 | head = new Node(array[0]); |
036 | Node *temp = head; |
037 | int i; |
038 | for ( i = 1; i < 3; i++ ) |
039 | { |
040 | temp->next = new Node(array[i]); |
041 | temp = temp->next; |
042 | } |
043 | |
044 | temp->next = NULL; |
045 | } |
046 | }; |
047 | |
048 | /*递归的合并两个有序链表*/ |
049 | Node * mergeLinkedList(Node *head1, Node *head2) |
050 | { |
051 | Node *p = NULL; |
052 | |
053 | if (head1 == NULL && head2 == NULL) |
054 | return p; |
055 | else if (head1 == NULL) |
056 | return head2; |
057 | else if (head2 == NULL) |
058 | return head1; |
059 | else |
060 | { |
061 | if (head1->data < head2->data) |
062 | { |
063 | p = head1; |
064 | p->next = mergeLinkedList(head1->next, head2); |
065 | } |
066 | else |
067 | { |
068 | p = head2; |
069 | p->next = mergeLinkedList(head1, head2->next); |
070 | } |
071 | |
072 | return p; |
073 | } |
074 | } |
075 | |
076 | /*打印链表的所有元素*/ |
077 | void printList(Node *head) |
078 | { |
079 | Node *temp = head; |
080 | while (temp != NULL) |
081 | { |
082 | cout<<temp->data<< " " ; |
083 | temp = temp->next; |
084 | } |
085 | } |
086 | |
087 | int main() |
088 | { |
089 | int array1[3] = {2,5,8}; |
090 | int array2[3] = {1,6,7}; |
091 | |
092 | /*构造两个有序链表--list1和list2*/ |
093 | LinkedList list1(array1); |
094 | LinkedList list2(array2); |
095 | |
096 | /*递归的将这两个有序链表合并成一个有序链表*/ |
097 | Node *new_head = mergeLinkedList(list1.head, list2.head); |
098 | |
099 | /*打印有序链表*/ |
100 | printList(new_head); |
101 | |
102 | return 0; |
103 | } |