您的位置:首页 > 职场人生

面试中常见链表题型整理

2013-03-29 12:11 537 查看
面试中常见链表题型整理

面试中常见链表题型如下:

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、检测单链表是否有环,如果有则返回入口结点

算法思想:用两个指针p1,p2同时指向链表的头部,p1一次移动一步,p2一次移动两步,如果最终p1和p2重合则说明链表有环,如果p2走到空指针(链表的结尾)则说明链表无环。如果最终p1和p2重合,使p2重新指向链表的头结点,然后p1和p2同时一次移动一步,当p1和p2再次重合时该节点指针就是环的入口节点指针。

证明思路:在p2和p1第一次相遇的时候,假定p1走了n步,环路的入口是在p步的时候经过的,那么有p1走的路径: p+c = n;(c为p1和p2相交点,距离环路入口的距离)p2走的路径: p+c+k*L = 2*n;(L为环路的周长,k是整数)显然,如果从p+c点开始,p1再走n步骤的话,还可以回到p+c这个点,同时p2从头开始走的话,经过n步,也会达到p+c这点。显然在这个步骤当中p1和p2只有前p步骤走的路径不同,所以当p1和p2再次重合的时候,必然是在链表的环路入口点上。

判断链表是否有环

bool  IsExitsLoop(slist * head)
{
slist * slow = head ,  * fast = head;
while  ( fast  &&  fast -> next )
{
slow  =  slow -> next;
fast  =  fast -> next -> next;
if  ( slow  ==  fast )  break ;
}
return   ! (fast  ==  NULL  ||  fast -> next  ==  NULL);
}


如果有环返回入口结点

slist *  FindLoopPort(slist * head)
{
slist * slow  =  head,  * fast  =  head;
while  ( fast  &&  fast -> next )
{
slow  =  slow -> next;
fast  =  fast -> next -> next;
if  ( slow  ==  fast )  break ;
}

if  (fast  ==  NULL  ||  fast -> next  ==  NULL)
return  NULL;
slow  =  head;
while  (slow  !=  fast)
{
slow  =  slow -> next;
fast  =  fast -> next;
}

return  slow;
}


 

4、给单链表建环

//找到有环节点,并解环,返回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、检测两条链表是否相交,有则返回交点

常见思路:

一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。

二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。

#include <iostream>
using namespace std;

/*节点的类定义*/
class Node
{
public:
int data;
Node * next;
Node(int data)
{
this->data=data;
}
};

/*链表的类定义*/
class List
{
public:
Node * head;//头结点指针
Node * tail;//尾结点指针

/*用一个整形数组作为参数的构造函数*/
List(int array[],int length)
{
head=new Node(array[0]);
Node * temp=head;
int i;
for(i=1;i<length;i++)
{
temp->next=new Node(array[i]);
temp=temp->next;
}
temp->next=NULL;
tail=temp;
}

/*查找指定位置的节点,并返回指向该节点的指针*/
Node * FindNode(int index)
{
Node * temp=head;
while(--index)
temp=temp->next;
return temp;
}
};

/*判断链表是否有环,如果有环则返回环的首结点指针,否则返回NULL值*/
Node * FindCircle(List list)
{
Node * p1,* p2;
p1=list.head;
p2=list.head;

/*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/
do
{
if(p2->next!=NULL&&p2->next->next!=NULL)
{
p2=p2->next->next;
p1=p1->next;
}
else
return NULL;
}
while(p1!=p2);

/*求出环的起点节点,并将其返回*/
p2=list.head;
while(p1!=p2)
{
p2=p2->next;
p1=p1->next;
}
return p1;
}

/*判断两个链表是否交叉,如果交叉返回交叉节点,否则返回NULL。*/
Node * FindCross(List list1,List list2)
{
list1.tail->next=list1.head;//将list1变成有环链表

Node * p1,* p2;
p1=list2.head;
p2=list2.head;

/*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/
do
{
if(p2->next!=NULL&&p2->next->next!=NULL)
{
p2=p2->next->next;
p1=p1->next;
}
else
return NULL;
}
while(p1!=p2);

/*求出环的起点节点,并将其返回*/
p2=list2.head;
while(p1!=p2)
{
p2=p2->next;
p1=p1->next;
}
return p1;
}

int main()
{
/*构造一个有环链表,并查找环的起始节点*/
int array[8]={1,2,3,4,5,6,7,8};
List list(array,sizeof(array)/sizeof(int));//构造一个链表
list.tail->next=list.FindNode(5);//将该链表构造成一个有环链表
Node * temp=FindCircle(list);//查找环的起始节点
if(temp==NULL)
cout<<"No cirle exists in the list."<<endl;
else
cout<<"There is a circle in the list , and the value of the join_point is "<<temp->data<<endl;

/*构造两个链表,然后使这两个链表交叉。最后查找交叉节点。*/
int array1[8]={1,2,3,4,5,6,7,8};
int array2[5]={9,10,11,12,13};
List list1(array1,sizeof(array1)/sizeof(int));//构造链表list1
List list2(array2,sizeof(array2)/sizeof(int));//构造链表list2
list2.tail->next=list.FindNode(3);//使这两个链表交叉
temp=FindCross(list,list2);//查找这两个链表的交叉节点
if(temp==NULL)
cout<<"These two lists dose not cross."<<endl;
else
cout<<"These two lists cross with each other , and the value of the corss_point is "<<temp->data<<endl;
return 0;
}


//检测两条链表是否相交,是则返回第一个交点,否则返回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、合并两个有序链表

按 Ctrl+C 复制代码
/*

递归实现:

①算法思想:

递归终止条件:若head1为空,返回head2指针(head);若head2为空,返回head1指针(head)

递归过程:

 若head1->data>head2->data;  head 指针应该指向head2所指向的节点,而且head->next应该指向head1和head2->next两个链表的合成序列的头指针;

 否则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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: