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

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

单链表面试题(进阶)

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;
}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩生殖器痒经常用手抓怎么办 孩子在幼儿园生殖器官受伤怎么办? 被骗了3000块钱怎么办 小说 月经来了想体检怎么办 尿检的时候遇上月经期怎么办 消防兵改革那新兵怎么办 教师资格证体检有问题怎么办 检兵合格还在上学怎么办 运动后肌肉肿了怎么办 打架用力过猛肌肉疼痛怎么办 军检只要一项不合格怎么办 体检身高差一厘米怎么办 体检身高差两公分怎么办 体检身高差10厘米怎么办 孩子的爸爸总是打游戏怎么办 拉屎屁眼疼还有血怎么办 家里冼澡要等好多冷水怎么办 孕晚期小孩头大怎么办 报考警校体检不合格退回怎么办? 入职体检视力0.1怎么办 屁扒骨折疼要怎么办 宝宝发高烧怎么办能快速退烧 屁股上长了纹路怎么办 手机充电头歪了怎么办 屁股挠烂了化脓怎么办 手机充电那坏了怎么办 孩子在学校被老师冤枉怎么办 初中学校不好我该怎么办 天气太热屁股淹了怎么办 骑车骑的屁股疼怎么办 爬山时屁股摔紫青了怎么办 宝宝不肯脱裤子拉粑粑怎么办 国家对无地农民怎么办 生完孩子骨架变大怎么办 17岁长高很慢怎么办? 出月子腿着凉了怎么办 脚着凉了脚疼怎么办 腿着凉了特别疼怎么办 孩子骨龄大2两年怎么办 和人吃饭很尴尬怎么办 头不自觉向右偏怎么办