链表相关笔试面试题

1.判断两个链表是否相交

    两个链表是否相交可分为以下几种情况
    (1)两个链表都不带环,此时两个链表所对应的最后一个节点是相等的
    (2)两个链表一个带环,一个不带环,两个链表一定不相交
    (3)连个链表都带环,如果相交则可以分为以下三种情况
      1)两个链表在环外相交, 此时链表1 和链表2 对应的环的入口地址是相等的
      2)两个链表在换上相交,此时从一个环的入口地址出发,一定可以到达另一个环的入口
      3)如果不是以上两种情况,则连个链表一定不相交

/***链表是否相交没有环 **/int LinkListHasCrossWithCircle(LinkNode* head1, LinkNode* head2)
{if(head1 == NULL || head2 == NULL){return 0;}LinkNode* cur1 = head1;while(cur1 -> next != NULL){cur1 = cur1 -> next;}LinkNode* cur2 = head2;while(cur2 -> next != NULL){cur2 = cur2 -> next;}if(cur1 == cur2){return 1;}return 0;
}   /*** 链表是否相交,不确定有没有环 **/int LinkListHasCrossWithCircle2(LinkNode* head1, LinkNode* head2)
{if(head1 == NULL || head2 == NULL){return 0;//两链表至少一个为空}                                                                                                                                                          LinkNode* circle1 = LinkListHasCircle(head1);LinkNode* circle2 = LinkListHasCircle(head2);//两个链表都不带环if(circle1 == NULL && circle2 == NULL){return LinkListHasCrossWithCircle(head1, head2);}//两链表都带环else if(circle1 != NULL && circle2 != NULL){//在环外相交LinkNode* entry1 = LinkListGetCircleEntry(head1);LinkNode* entry2 = LinkListGetCircleEntry(head2);if(entry1 == entry2){return 1;}//再换上相交else if(entry1 != entry2){LinkNode* cur1 = entry1;//从一个环入口点出发可以到达另外一个环入口点,则证明相交while(cur1 != entry2){cur1 = cur1 -> next;}return 1;}//不是上述情况则没有相交return 0;}//一个带环一个不带环,则一定不相交else if( ( circle1 == NULL && circle2 != NULL )|| (circle1 != NULL && circle2 == NULL)){return 0;}
}

                       这里写图片描述

2.求链表的交点

    求换的交点和上述判断是否有环是一个思路,可以分为一下几种情况
    (1)两个链表都不带环的情况下,先利用上面的函数判断出连个链表是否相交,再求出两个链表的长度 size1, size2,再将两个链表的长度做差(长的减短的)得到一个大于等于0 的数 offset,再让分别定义两个指针 cur1, cur2, 指向 head1, head2, 然后让长链表对应的 cur1(假定cur1所指的链表长) 先走 offset 步,cur2 不动,cur1 每走一步 offset 就减1, 等到 offset 等于 0 的时候这个时候就说明两个指针cur1, cur2 都相对于交点的距离相等, 这个时候让 cur1, cur2 一起向后走,当它们两个指针所对应的节点相同时, 此时这个相同的节点就是两个链表的交点
    (2)当两个链表一个带环,一个不带环时, 此时链表一定不相交,直接返回空
    (3)当两个链表都有环时,分为一下三种情况
      1)两个链表在环外相交,此时的交点求法如图所示

     这里写图片描述
      2)连个链表在环上相交
                         这里写图片描述
      3)如果不是以上两种,那么一定不相交

/**                                                                                                                                                             *环的相交点不带环**/LinkNode* LinkListCrossPoint(LinkNode* head1, LinkNode* head2)
{if(head1 == NULL || head2 == NULL){return NULL;//两链表至少一个为空}int len1 = LinkListSize(head1);int len2 = LinkListSize(head2);LinkNode* cur1 = head1;LinkNode* cur2 = head2;int offset = 0;if(len1 > len2){offset = len1 - len2;for(; offset > 0; cur1 = cur1 -> next){offset--;}}else if(len2 > len1){offset = len2 - len1;for(; offset > 0; cur2 = cur2 -> next){offset--;}}for(; cur1 != cur2; cur1 = cur1 -> next, cur2 = cur2 -> next){;}return cur1;                                                                                                                                               
}/**                                                                                                                                                             *环的相交点带环不带环不确定**/LinkNode* LinkListCrossPoint2(LinkNode* head1, LinkNode* head2)
{if(head1 == NULL || head2 == NULL)                                                                                                                       {    return NULL;//两链表至少一个为空,一定不相交}    LinkNode* entry1 = LinkListGetCircleEntry(head1);LinkNode* entry2 = LinkListGetCircleEntry(head2);//如果两个都不带环,直接用第一个版本if(entry1 == NULL && entry2 == NULL){    return LinkListCrossPoint(head1, head2);}    //如果一个带环,一个不带环,一定不相交if(( entry1 == NULL && entry2 != NULL ) || ( entry1 != NULL && entry2 == NULL )){    return NULL;}    //如果两个都有环LinkNode* cur1 = head1;LinkNode* cur2 = head2;if(entry1 != NULL && entry2 != NULL){    
//环外相交if(entry1 == entry2){LinkNode* end = entry1;int size1 = 0;int size2 = 0;for(; cur1 != end; cur1 = cur1 -> next){size1++;}size1 = size1 + 1;for(; cur2 != end; cur2 = cur2 -> next){size2++;}size2 = size2 + 1;int offset =  0;if(size1 > size2){offset = size1 - size2;                                                                                                                      for(cur1 = head1, cur2 = head2; offset > 0; offset--){cur1 = cur1 -> next;}for(; cur1 != end && cur1 != cur2; cur1 = cur1 -> next, cur2 = cur2 -> next){;}return cur1;}else if(size2 > size1){offset = size2 - size1;for(cur1 = head1, cur2 = head2; offset > 0; offset--){cur2 = cur2 -> next;}for(; cur1 != end && cur1 != cur2; cur1 = cur1 -> next, cur2 = cur2 -> next){;}return cur1;}else//size1  = size2{for(cur1 = head1, cur2 = head2; cur1 != cur2 && cur1 != end && cur2 != end; cur1 = cur1 -> next, cur2 = cur2 -> next){                                                                                                                                            ;}return cur1;}}//环内相交,相交点就是入口else if(entry1 != entry2){LinkNode* cur = entry1;for(; cur != entry2; cur = cur -> next){;}return entry2;cur = entry2;for(; cur != entry1; cur = cur -> next){;}return entry1;}//不是上述两种情况,则不相交else{return NULL;}                                                                                                                                                    }
}

                这里写图片描述

3.求连个链表的交集

    求交集就是分别定义两个指针 cur1, cur2,指向两个对应的链表的首元素, 然后将 cur1 和 cur2 所指的链表的 data 进行比较, 如果相等, 将这个结点插入到一个新链表中, 然后两个指针 cur1, cur2, 一起向后走一步,如果不相等, 就将 data 值小的那个指针向后移动, 而另外一个指针不动, 在进行比较,重复以上动作,直到 cur1 或者 cur2 两个中其中一个为空,则停止循环

LinkNode* LinkListUnionSet(LinkNode* head1, LinkNode* head2)
{if(head1 == NULL || head2 == NULL){return NULL;//两个链表至少有一个为空}LinkNode* cur1 = head1;LinkNode* cur2 = head2;LinkNode* new_head = NULL;LinkNode* new_tail = NULL;while(cur1 != NULL && cur2 != NULL){if(cur1 -> data < cur2 -> data){cur1 = cur1 -> next;}else if(cur1 -> data > cur2 -> data){cur2 = cur2 -> next;}else{if(new_head == NULL){new_head = LinkNodeCreat(cur1 -> data);new_tail = new_head;}else{new_tail -> next = LinkNodeCreat(cur1 -> data);new_tail = new_tail -> next;}cur1 = cur1 -> next;                                                                                                                               cur2 = cur2 -> next;}}return new_head;
}

这里写图片描述

4. 拷贝复杂链表

    先看一下复杂链表的数据结构

typedef struct ComplexNode
{LinkNodeType data;struct ComplexNode* next;struct ComplexNode* random;
}ComplexNode;

    复杂链表中除了 data, next, 之外,还有一个 random, 它可能指向链表中的如何一个节点, 还可能指向空。
    在进行复杂链表的拷贝时, 可以采用下面的方法, 先将复杂链表按照简单链表进行复制,将其复制到一个新链表中, 此时的新链表还是一个简单链表, 然后再遍历旧链表,求出每一个节点所对应的 random 相对于头节点的偏移量, 再遍历新链表, 根据所求得的偏移量确定新链表中的 random 的指针的指向。

/*** 复杂链表的拷贝**/                                                                                                                                                            ComplexNode* ComplexCopy(ComplexNode* head)
{if(head == NULL){return NULL;//空链表}ComplexNode* cur = head;ComplexNode* new_head = NULL;ComplexNode* new_tail = NULL;while(cur != NULL){if(new_head == NULL){new_head = head ;new_tail = new_head;}else{new_tail -> next = cur;new_tail = new_tail -> next;}cur = cur -> next;}//求每个random相对于头结点的偏移量int offset = 0;ComplexNode* new_cur = new_head;for(cur = head; cur != NULL; cur = cur -> next,new_cur = new_cur -> next){//求出每个结点相对于head的偏移量offset = Diff(head, cur -> random);//修改新链表中的random的值new_cur -> random = Step(new_head, offset);}return new_head;
}/*                                                                                                                                                             ** 通过offset找到random**/ComplexNode* Step(ComplexNode* head, int offset)
{if(head == NULL){    return NULL;//空链表}    if(offset == -1){    return NULL;}    ComplexNode* cur = head;ComplexNode* random = head;//让 random 走 offset 步,再将 cur -> random = randomfor(; offset > 0; offset --){    random = random -> next;}    return random; 
}/*** 求出每个结点相对于head的偏移量**/int Diff(ComplexNode* head, ComplexNode* random)
{if(head == NULL){return -2;}if(random == NULL){return -1;}ComplexNode* cur = head;ComplexNode* new_cur = random;int count = 0;while(cur != new_cur){count++;cur = cur -> next;}return count;
}

这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384097.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux经典问题—五哲学家就餐问题

http://m.blog.csdn.net/aspenstars/article/details/70149038 一、问题介绍 由Dijkstra提出并解决的哲学家进餐问题(The Dinning Philosophers Problem)是典型的同步问题。该问题是描述有五个哲学家共用一张圆桌&#xff0c;分别坐在周围的五张椅子上&#xff0c;在圆桌上有五…

修改之前的myshell使之支持输入输出重定向

1.open函数     这个函数是打开一个文件&#xff08;文件名叫pathname),以 flag 权限打开&#xff0c;flag 包括了以下几种 O_RDONLY&#xff08;只读&#xff09;, O_WRONLY&#xff08;只写&#xff09;, O_RDWR&#xff08;读写&#xff09;&#xff0c;当文件打开成…

链表相关的算法题大汇总 — 数据结构之链表奇思妙想

http://blog.csdn.net/lanxuezaipiao/article/details/22100021基本函数&#xff08;具体代码实现见后面&#xff09; 1&#xff0c;构造节点 //定义节点类型 struct Node { int value; Node*next; }; 2&#xff0c;分配节点 //之所以要分配节点原因是需要在分配函数中…

匿名管道

1.进程通信的目的 (1) 数据传输: 一个进程需要将它的数据传输给另一个进程     (2) 资源共享: 多个进程之间共享同样的资源     (3) 通知事件: 一个进程需要向另一个或一组进程发送消息, 通知它们发生了什么事情 2.管道 管道是一种进程之间通信的一种方式, 我们把从…

将信号量代码生成静态库以及动态库

1.信号量相关代码生成静态库 2.信号量相关代码生成动态库

C++11 标准新特性:Defaulted 和 Deleted 函数

https://www.ibm.com/developerworks/cn/aix/library/1212_lufang_c11new/index.html Defaulted 函数 背景问题 C 的类有四类特殊成员函数&#xff0c;它们分别是&#xff1a;默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符。这些类的特殊成员函数负责创建、初始化、…

顺序表实现栈相关操作

1.栈的相关概念 栈是一种特殊的线性表, 其中只允许在固定的一端进行插入和删除元素.进行数据插入和删除的一端叫做栈顶, 另一端成为栈底. 不含任何元素的栈称为空栈, 栈又称为先进先出的线性表. 2. 顺序栈的结构 3. 顺序栈的具体操作 (1). 数据结构 typedef char SeqStackTyp…

双向带环带头结点的链表实现栈

1. 数据结构 利用带头结点带环的结点实现栈的相关操作.因此, 每一个结点包括了一个前驱, 一个后继, 还有一个数据成员 typedef char DLinkStackType;typedef struct DLinkStack {DLinkStackType data;struct DLinkStack* next;struct DLinkStack* prev; }DLinkStack;2. 初始化…

C++11 标准新特性:委派构造函数

https://www.ibm.com/developerworks/cn/rational/1508_chenjing_c11/index.html陈 晶2015 年 8 月 11 日发布WeiboGoogle用电子邮件发送本页面 1本文首先介绍了在委派构造函数提出之前类成员构造所面临的问题&#xff0c;再结合实例介绍了委派构造函数的用法&#xff0c;并说明…

顺序表实现队列

一. 队列相关概念 队列是只允许在一段进行插入元素, 在另一端进行删除元素的线性表,即只允许对队列进行尾插,头删的操作.队列具有先进先出, 后进后出的特性.          1.初始化 void SeqQueInit(SeqQue* q) {if(q NULL){return;//非法输入}q -> head 0;q -> …

链表实现队列

上篇博客是用顺序表实现队列, 现在用双向带头结点带环链表实现对队列的出队列, 入队列, 取队首元素, 以及销毁队列的相关操作 1.初始化链表 void DLinkQueInit(DLinkQue** q) {if(q NULL){return;//非法输入}if(*q NULL){return;//非法输入带头结点的链表至少有一个傀儡结点…

HDU - 1796——容斥原理+二进制枚举

【题目描述】 Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N12, and M-integer set is {2,3}, so there is another set {2,3,4,…

信号的基本概念以及信号的产生

一. 信号产生的场景 1. 用户输入命令, 在shell 启动一个前台进程      2. 当用户按一下 Ctrl C 的时候,从键盘产生一个硬件中断      3. 此时CPU 正在执行这个进程的带代码, 则该进程的执行代码暂停执行, CPU 从用户态切换到内核态处理该硬件中断.      4. 中断…

信号的阻塞

一. 阻塞信号 1.信号的相关概念     (1) 递达: 实际执行信号的处理动作称为信号的递达     (2) 未决: 信号从产生到递达之间的过程叫做信号的未决     (3) 阻塞: 进程可以选择阻塞某个信号, 被阻塞的信号产生时将保持在未决状态, 直到进程解除该信号的屏蔽, 才…

信号的捕捉以及SIGCHLD信号

一. 信号的捕捉定义 用户提供一个处理函数, 要求内核在处理信号时必须切换到用户态,执行这个函数, 这种方式就叫做信号的捕捉 二. 图解信号的捕捉过程 1. 由上图可以看出,当处理信号的执行动作时用户自定义的时候,此时就需返回该函数去调用该函数, 这就叫做信号的捕捉. 以前我…

最小栈的实现

所谓最小栈, 就是当前栈顶元素最小, 我们可以这样做, 每次在入栈之前, 将待入栈元素与栈顶元素相比, 每次现将待入栈的元素先入栈, 再将带入栈的元素和较小的元素入栈, 这样就可以保证每次栈顶元素是最小元素. 在出栈的时候规定每次出栈两个元素,这样就可以保证在出栈之后栈顶元…

用C++实现单链表的创建、逆置和输出 的两种方法

http://blog.csdn.net/lfeng_coding/article/details/47300563 题目描述&#xff1a;在已知单链表头节点的情况下&#xff0c;设计算法逆置单链表并输出 方法一&#xff1a;采用首先将头节点指向空&#xff0c;让其变为尾节点&#xff0c;然后利用中间节点 p、q 将其后的节点一…

两个栈实现一个队列

利用两个栈实现一个队列思路是这样的. 首先这个队列包含两个栈, 然后一个栈用来入队列, 一个栈用来出队列 typedef struct QueBy2Stack {SeqStack input;SeqStack output; }QueBy2Stack; 1. 初始化 void QueBy2StackInit(QueBy2Stack* stack) {if(stack NULL){return;//非法…

Linux--线程死锁

http://blog.csdn.net/gebushuaidanhenhuai/article/details/73799824 线程为什会死锁&#xff1f;&#xff1f;“锁”又是什么东西&#xff1f;我们这篇博客主要讲一下为什么要给线程加锁&#xff0c;为什么会出现线程死锁&#xff0c;线程死锁怎么解决。 互斥锁 在我的上篇博…

两个队列实现一个栈

用两个队列实现一个栈的原理是这样的. 规定两个队列, 必须有一个队列是非空, 一个队列是空.每次入栈时必须往非空队列中入, 而每次出栈时, 必须将非空队列里的元素装到空队列中, 直到非空队列中只有一个元素时, 此时就将剩下的这个元素出栈即可. 而取栈顶元素时, 和出栈一样, 先…