面试中常见的链表题目

最近参加面试遇到的一些常见的单链表题目,总结思路和实现代码。

1.单链表的反序

2.给单链表建环

3.检测单链表是否有环

4.给单链表解环

5.检测两条链表是否相交

6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)

7.合并两个有序链表


1.单链表的反序

01//逆转链表,并返回逆转后的头节点  
02node* 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//方法二
02node *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  
02bool 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//检测单链表是否有环,快慢指针  
02bool 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节点,只可能是尾环  
03bool 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)的位置开始遍历,第一个相等的指针为目标节点  
04node* 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:当传入节点为尾节点,无法用此方法删除  
04bool 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  
0071 若head1->data>head2->data;  head 指针应该指向head2所指向的节点,而且head->next应该指向head1和head2->next两个链表的合成序列的头指针;
008  
0092 否则head 指针应该指向head1所指向的节点,而且head->next应该指向head->next和head2两个链表的合成序列的头指针;
010*/
011#include <iostream>
012using namespace std;
013  
014/*节点的类定义*/
015class Node
016{
017public:
018    int data;
019    Node *next;
020    Node(int data)
021    {
022        this->data = data;
023    }
024};
025  
026/*链表的类定义*/
027class LinkedList
028{
029public:
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/*递归的合并两个有序链表*/
049Node * 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/*打印链表的所有元素*/
077void printList(Node *head)
078{
079    Node *temp = head;
080    while(temp != NULL)
081    {
082        cout<<temp->data<<"  ";
083        temp = temp->next;
084    }
085}
086  
087int 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}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值