最近参加面试遇到的一些常见的单链表题目,总结思路和实现代码。
1.单链表的反序
2.给单链表建环
3.检测单链表是否有环
4.给单链表解环
5.检测两条链表是否相交
6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)
7.合并两个有序链表
1.单链表的反序
//逆转链表,并返回逆转后的头节点
node* reverse(node *head)
{
if(head == NULL || head->next == NULL)
{
return head;
}
node *cur = head;
node *pre = NULL;
node *tmp;
while(cur->next)
{
tmp = pre;
pre = cur;
cur = cur->next;
pre->next = tmp; //操作pre的next逆转
}
cur->next = pre; //结束时,操作cur的next逆转
return cur;
}
//方法二
node *reverse(node *head)
{
node *p, *q, *r;
p = head;
q = p->next;
while(q != NULL)
{
r = q->next;
q->next = p;
p = q;
q = r;
}
head->next = NULL;
head = p;
return head;
}
2.给单链表建环
//给单链表建环,让尾指针,指向第num个节点,若没有,返回false
bool bulid_looplink(node *head, int num)
{
node *cur = head;
node *tail = NULL;
int i = 0;
if(num <= 0 || head == NULL)
{
return false;
}
for(i = 1; i < num; ++i)
{
if(cur == NULL)
{
return false;
}
cur = cur->next;
}
tail = cur;
while(tail->next)
{
tail = tail->next;
}
tail->next = cur;
return true;
}
3.检测单链表是否有环
//检测单链表是否有环,快慢指针
bool detect_looplink(node *head)
{
node *quick_node = head->next, *slow_node = head;
if(head == NULL || head->next == NULL)
{
return false;
}
while(quick_node != slow_node)
{
if(quick_node == NULL || slow_node == NULL)
break;
quick_node = quick_node->next->next;
slow_node = slow_node->next;
}
if(quick_node != NULL && slow_node != NULL) //非尾节点相遇
return true;
return false;
}
4.给单链表解环
ps:为了增加节点位图的效率,本应使用hash或则红黑树,这里不造车了,直接用 set容器
//找到有环节点,并解环,找到并解环,返回true,无环,返回false
//思路:先找到环节点:被2个节点指向的节点(一定有环的条件)ps:不考虑中间环,因为只有一个next节点,只可能是尾环
bool unloop_link(node *head)
{
set<node *> node_bitmap; //node的地址位图
unsigned int num = 0;
node *cur = head, *pre = NULL;
while(cur != NULL)
{
if(!node_bitmap.count(cur) ) //该节点未被遍历过
{
node_bitmap.insert(cur);
++num;
}
else //指向已被遍历过的节点,此时pre节点为尾节点
{
pre->next = NULL;
return true;
}
pre = cur;
cur = cur->next;
}
return false;
}
5.检测两条链表是否相交
//检测两条链表是否相交,是则返回第一个交点,否则返回NULL
//思路:把2个链表各遍历一遍,记下长度length1和length2,若2者的尾节点指针相等,则相交。
// 之后再把长的链表从abs(len1-len2)的位置开始遍历,第一个相等的指针为目标节点
node* detect_intersect_links(node *first_link, node *second_link)
{
int legnth1 = 1, length2 = 1, pos = 0;
node *cur = NULL, *longer_link = first_link, *shorter_link = second_link;
if(first_link == NULL || second_link == NULL)
{
return NULL;
}
while(first_link->next || second_link->next) //遍历2个链表
{
if(first_link->next)
{
first_link = first_link->next;
++legnth1;
}
if(second_link->next)
{
second_link = second_link->next;
++length2;
}
}
if(first_link != second_link) //比较尾节点
{
return NULL;
}
pos = legnth1 - length2;
if(legnth1 < length2) //保证 longer_link为长链表
{
pos = length2 - legnth1;
cur = longer_link;
longer_link = shorter_link;
shorter_link = cur;
}
while(pos-- > 0)
longer_link = longer_link->next;
while(longer_link || shorter_link)
{
if(longer_link == shorter_link) //找到第一个交点
{
return longer_link;
}
longer_link = longer_link->next;
shorter_link = shorter_link->next;
}
return NULL;
}
6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)
//无头节点,随机给出单链表中一个非头节点,删除该节点,当传入空节点,或者尾节点时,返回false
//思路:由于没有头节点,非循环单链表,无法获取目标节点的前节点,所以只能把它的next节点数据前移,并删除next节点
//ps:当传入节点为尾节点,无法用此方法删除
bool withouthead_delete_node(node *target_node)
{
node *cur = NULL;
if(target_node == NULL || target_node->next == NULL) //空节点或者尾节点,失败
{
return false;
}
cur = target_node->next;
target_node->name = cur->name;
target_node->next = cur->next;
delete cur;
return true;
}
7.合并两个有序链表
/*
递归实现:
①算法思想:
递归终止条件:若head1为空,返回head2指针(head);若head2为空,返回head1指针(head)
递归过程:
1 若head1->data>head2->data; head 指针应该指向head2所指向的节点,而且head->next应该指向head1和head2->next两个链表的合成序列的头指针;
2 否则head 指针应该指向head1所指向的节点,而且head->next应该指向head->next和head2两个链表的合成序列的头指针;
*/
#include <iostream>
using namespace std;
/*节点的类定义*/
class Node
{
public:
int data;
Node *next;
Node(int data)
{
this->data = data;
}
};
/*链表的类定义*/
class LinkedList
{
public:
Node *head;
/*用一个整形数组作为参数的构造函数*/
LinkedList(int array[])
{
head = new Node(array[0]);
Node *temp = head;
int i;
for( i = 1; i < 3; i++ )
{
temp->next = new Node(array[i]);
temp = temp->next;
}
temp->next = NULL;
}
};
/*递归的合并两个有序链表*/
Node * mergeLinkedList(Node *head1, Node *head2)
{
Node *p = NULL;
if(head1 == NULL && head2 == NULL)
return p;
else if(head1 == NULL)
return head2;
else if(head2 == NULL)
return head1;
else
{
if(head1->data < head2->data)
{
p = head1;
p->next = mergeLinkedList(head1->next, head2);
}
else
{
p = head2;
p->next = mergeLinkedList(head1, head2->next);
}
return p;
}
}
/*打印链表的所有元素*/
void printList(Node *head)
{
Node *temp = head;
while(temp != NULL)
{
cout<<temp->data<<" ";
temp = temp->next;
}
}
int main()
{
int array1[3] = {2,5,8};
int array2[3] = {1,6,7};
/*构造两个有序链表--list1和list2*/
LinkedList list1(array1);
LinkedList list2(array2);
/*递归的将这两个有序链表合并成一个有序链表*/
Node *new_head = mergeLinkedList(list1.head, list2.head);
/*打印有序链表*/
printList(new_head);
return 0;
}