最近参加面试遇到的一些常见的单链表题目,总结思路和实现代码。
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 |
} |
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 |
} |