链表面试题(进阶)&&复杂链表的复制

来源:互联网 发布:rgb转化到hsv的算法 编辑:程序博客网 时间:2024/06/16 00:52

单链表面试题(进阶)

1、判断单链表是否带环?若带环,求环的长度?求环的入口点?

2、判断两个链表是否相交,若相交,求交点。(假设链表不带环)

3、判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。

//ps: 复杂链表的结构

struct ComplexNode


int _data ; // 数据 
struct ComplexNode * _next; // 指向下一个节点的指针 
struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空) 
};

1、判断单链表是否带环?若带环,求环的长度?求环的入口点?

 
在链表的头结点定义一个快指针和慢指针,让慢指针一次走两步,快指针一次走两步,如果链表带环,则快指针一定会追上慢指针的,如果不带环则快指针先到表尾。若是求环的长度时,在快指针和慢指针在环内相交时,记住这个点,然后让慢指针从这个点开始再走一圈,即可求出环的长度。

ListNode *check_Ring(ListNode *plist)
{//1、空或者只有一个 2、带环链表 3、不带环
if(plist == NULL && plist->next == NULL)
{
printf("不带环\n");
return 0;
}
else
{
ListNode *slow = plist;
ListNode *fast = plist;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
return slow;
}
return NULL;
}
}

Datatype LengthList(ListNode *plist)
{//求环长读。先求慢节点的位置,然后让慢节点走一圈就是环的长度
assert(plist);
if(plist->next == NULL)
return 1;
else
{
ListNode *slow = check_Ring(plist);
ListNode *next = slow->next;
int step = 1;
while(slow != next)
{
step++;
next = next->next;
}
return step;
}
}

求环的入口点,可以由下面的公式求


ListNode *InRingNode(ListNode *plist)
{//要是环至少得有两个及以上的节点
if(plist == NULL && plist->next == NULL)
return NULL;
else
{
ListNode *fast = check_Ring(plist);;
while(plist != fast)
{
plist = plist->next;
fast = fast->next;
}
return plist;
}
}

2、判断两个链表是否相交,若相交,求交点。(假设链表不带环)


先让两个链表遍历一遍分别求出尾指针,如果不相同则不相交,相同则分别求出两个链表的长度,然后让长的先走他们的长度之差步,然后再一起走,若走到节点相同时就是交点。

ListNode *FindpointList(ListNode *plist1, ListNode *plist2)
{
assert(plist1 && plist2);
ListNode *tail1 = plist1;
ListNode *tail2 = plist2;
int i = 1;
int j = 1;
while(tail1->next)//先遍历链表求长度
{
tail1 = tail1->next;
++i;
}
while(tail2->next)
{
tail2 = tail2->next;
++j;
}
if(tail1 != tail2)//如果两个尾指针相同则在往前找交点
return NULL;
else
{
int num = abs(i-j);
if(i >= j)//哪个长度大,哪个就先走
{
while(num--)
{
plist1 = plist1->next;
}
}
else
{
while(num--)
{
plist2 = plist2->next;
}
}
while(plist1 != plist2)//当两个节点相同时就是交点
{
plist1 = plist1->next;
plist2 = plist2->next;
}
return plist1;
}
}

3、判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

判断两个可能带环的链表相交问题,先分析清楚有几种可能性然后再求

1、1、两个连表达不带环(这种情况已经分析) 
2、一个链表带环,另一个不带环 
3、两个链表都带环 
3.1、两个不想交 
3.2、有一个交点在环外 
3.3、两个交点在环内


ListNode *IsCrossList(ListNode *plist1, ListNode *plist2)
{
//1、两个连表达不带环(这种情况已经分析)
//2、一个链表带环,另一个不带环
//3、两个链表都带环
// 3.1、两个不想交
// 3.2、有一个交点在环外
// 3.3、两个交点在环内
assert(plist1);
assert(plist2);
ListNode *list1 = check_Ring(plist1);
ListNode *list2 = check_Ring(plist2);

if((list1 != NULL && list2 == NULL) || ((list1 == NULL) && (list2 != NULL)))
{//若两个链表一个带环一个不带环则不相交
return NULL;
}
if(list1 != NULL && list2 != NULL)
{
ListNode *cur1 = InRingNode(plist1);
ListNode *cur2 = InRingNode(plist2);
if(cur1 == cur2)//若交点相同则在环外相交
{
ListNode *slow = list1;
slow->next = NULL;
ListNode *plist = FindpointList(plist1, plist2);
return plist;
}
else//交点不相同则在环内
{
Datatype num = LengthList(plist1);
ListNode *tmp = cur1;
while(--num)//当一圈走完都没有发现另一个入口点,那就是不相交
{
while(tmp != cur2)
{
tmp = tmp->next;
}
return cur1;
}
}
}
return NULL;
}

4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。

//ps: 复杂链表的结构 
struct ComplexNode 

int _data ; // 数据 
struct ComplexNode * _next; // 指向下一个节点的指针 
struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空) 
};

用以下步骤来实现复杂链表的复制

1、先创建一个和每个节点都相同的节点

2、按顺序的将这些节点依次插到和它数据相同节点的后面,然后全部连接起来

3、操作这些“复制后”的节点,让每个节点的随机节点指向原节点的随机节点的下一位

4、分离复制的链表和原链表,返回复制后的链表


typedef struct ComplexNode 
{
Datatype _data ; // 数据
ComplexNode * _next; // 指向下一个节点的指针
ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空)
}ComplexNode;


ComplexNode *buyNode(Datatype h)
{
ComplexNode *node = (ComplexNode *)malloc(sizeof(ComplexNode));
assert(node);
node->_data = h;
node->_next = NULL;
node->_random = NULL;
return node;
}

ComplexNode *CopyList(ComplexNode *plist)//复制链表
{
ComplexNode *cur = plist;
if(plist == NULL && plist->_next == NULL)
return NULL;
while(cur)//将创造的和前一个节点相同的节点全都连起来
{
ComplexNode *next = plist->_next;
ComplexNode *tmp = buyNode(cur->_data);
tmp->_next = cur->_next;
cur->_next = tmp;
cur = tmp->_next;
}
ComplexNode *newlist = plist;
ComplexNode *tail = NULL;
while(newlist != NULL)
{
ComplexNode *newcur = newlist->_next;
if(newlist->_random != NULL)
newcur->_random = newlist->_random->_next;
newlist = newcur->_next;
}
return plist;
}

ComplexNode *DetachList(ComplexNode *plist)//分离复制后的节点
{
ComplexNode *newlist = plist;
ComplexNode *next = newlist->_next;
ComplexNode *head = next;
if(newlist)
{
newlist->_next = next->_next;
newlist = newlist->_next;
}
while(newlist)
{
next->_next = newlist->_next;
next = next->_next;
newlist->_next = next->_next;
newlist = newlist->_next;
}
return head;
}
原创粉丝点击