链表常见面试题-C语言实现

来源:互联网 发布:淘宝韩版男装店铺 编辑:程序博客网 时间:2024/06/14 18:53

前面的博客已经介绍过了实现链表的一些相关的功能,所以在这里就不对链表多加解释说明了。

对于链表相关面试题这里解释几个有特点的题:

1.对于求查找链表的中间结点,要求只能遍历一次链表?

方式:使用两个指针,一个快指针,一个慢指针,快指针走两步慢指针走一步,这样当快指针指向结尾空指针的时候,慢指针刚好指向中间结点。

图示:


2.查找链表倒数第K个结点要求只能遍历一次链表?

方式:同样运用快慢指针,先让快指针走K-1次然后让快慢指针一起走,当fast->next==NULL时,慢指针刚好指向倒数第K个结点,注意这里的快指针还是一次走两步。

图示:


3判断一个链表是否带环,带环求环的入口点?

方式:还是对快慢指针的运用,让两个指针一直走,如果相遇则带环,否则不带环。因为快慢的指针速度不一样,如果带环他们都上了环相当于跑圈,速度不一样肯定会相遇,如果不带环快指针肯定先指向NULL,也不会相遇。

图示:


4.求环的入口点?

方式:还是使用快慢指针,不过这里需要用到快慢指针在环上的相遇点,具体过程如下图

图示:


当然这个题的解法还有很多,大家可以自己思考一下其他的方法

5.判断两个链表是否相交,求交点?

方式:这里还是对快慢指针的应用,具体过程如下图




接下来给出所有问题的代码

首先给出头文件List.h

#define _CRT_SECURE_NO_WARNINGS 1#ifndef __LIST_H__#define __LIST_H__#include<stdio.h>#include<stdlib.h>#include<assert.h>typedef int Datatype;typedef struct Node{Datatype data;struct Node *next;}Node,*PLinklist;void initList(PLinklist* pplist);//初始化头指针void pushback(PLinklist* pplist,Datatype);//尾插法void showlist(PLinklist pplist);//正顺打印结点void destory(PLinklist* pplist);//释放所开辟的结点void _showlist(PLinklist pplist);//逆序打印void delnotetail(PLinklist pos);//删除无头非尾结点PLinklist find_list(PLinklist pplist, Datatype d);//查找链表void inertfrontnode(PLinklist pos, Datatype d);//无头结点非尾结点前插入一个元素void josephcycle(PLinklist pplist,Datatype  k);//约瑟夫环void rever(PLinklist* pplist);//逆序链表void bubble(PLinklist pplist);//排序链表PLinklist Merge(PLinklist* pplist, PLinklist* pplists);//合并两个有序链表和并后也为空PLinklist findmiddle(PLinklist pplist);//查找中间结点void deletk(PLinklist pplist,int k);//查找倒数第K个结点.只能遍历一次离岸边PLinklist checkcircle(PLinklist pplist);//判断一个链表带不带环,带环返回两个指针相遇点的地址int getcirclelong(PLinklist meet);//如果有环求环的长度PLinklist findenterpoint(PLinklist pplist, PLinklist meet);//如果带环则找入口点,//meet为相遇点PLinklist checklist(PLinklist pplist, PLinklist pplists);//判断两条链表是否相交,相交返回交点#endif
接下来给出具体实现函数的文件List.c

#define _CRT_SECURE_NO_WARNINGS 1#include"List.h"void initList(PLinklist* pplist){*pplist = NULL;//pplist里面放的是指针变量head的地址,*pplist就是指针变量地址的值,在这里赋值为空}void pushback(PLinklist* pplist,Datatype d){Node *p = *pplist;//P里面存的是头指针的地址PLinklist cur= (PLinklist)malloc(sizeof(Node));//开辟第一个结点if (cur == NULL){perror("usr malloc ");exit(EXIT_FAILURE);}memset(cur, 0, sizeof(Node));cur->data = d;cur->next = NULL;if (p== NULL){*pplist = cur;//头结点的地址给头指针}else{while (p->next != NULL){p= p->next;}p->next = cur;}}void showlist(PLinklist pplist){Node *cur = pplist;while (cur != NULL){printf("%d--", cur->data);cur = cur->next;}}void destory(PLinklist* pplist){Node *cur = *pplist;//cur里面存的头指针的地址while (cur!= NULL){Node *p = cur;//保存第一个结点的地址cur = cur->next;//cur保存第二个结点的地址free(p);//}*pplist = NULL;}void _showlist(PLinklist pplist){if (pplist == NULL)return;else if (pplist->next == NULL)printf("%d ", pplist->data);else{_showlist(pplist->next);printf("%d ", pplist->data);}}PLinklist find_list(PLinklist pplist, Datatype d)//查找链表返回地址{Node *cur = pplist;while (cur){if (cur->data == d){return cur;}cur = cur->next;}return;}void delnotetail(PLinklist pos)//删除无头非尾结点{Node *cur = NULL;assert(pos->next);cur = pos->next;pos->data = cur->data;pos->next = cur->next;free(cur);}void inertfrontnode(PLinklist pos, Datatype d){assert(pos);Node *p = (PLinklist)malloc(sizeof(Node));if (p == NULL){perror("use malloc");exit(EXIT_FAILURE);}p->data = pos->data;pos->data = d;p->next = NULL;p->next = pos->next;pos->next = p;}void josephcycle(PLinklist pplist, Datatype  k)//约瑟夫环{Node *cur = pplist;Node *del = NULL;int count = 0;while (1){count = k;if (cur == cur->next)//剩一个数字退出{break;}while (count-2>0){cur = cur->next;--count;}printf("%d  ", cur->next->data);del = cur->next;cur->next = del->next;cur = cur->next;free(del);}printf("%d\n", cur->data);}void rever(PLinklist* pplist)//逆序链表{Node *cur = *pplist;Node *tem = NULL;Node *head = NULL;if ((cur == NULL) || (cur->next == NULL)){return;}while (cur){tem = cur->next;cur->next = head;head = cur;cur = tem;}*pplist = head;}void bubble(PLinklist pplist)//排序算法{int count = 1;Node *cur = pplist;Node *src = pplist;while (src->next != NULL){count++;src = src->next;}int i = 0,j=0;for (i = 0; i < count; i++){Node *cur = pplist;for (j = 0; j < count - 1 - i; j++){int temp = 0;if ((cur->data)>(cur->next->data)){temp = cur->data;cur->data = cur->next->data;cur->next->data = temp;}cur = cur->next;}}}PLinklist Merge(PLinklist* pplist, PLinklist* pplists)//链接两个有序链表{Node  *cur1 = *pplist;Node  *cur2 = *pplists;Node  *head = NULL;Node  *tail = NULL;if (cur1 == NULL&&cur2 == NULL)//两条都为空不合并return NULL;if (cur1 == cur2)return cur1;if (cur1 == NULL)return cur2;if (cur2 == NULL)return cur1;if (cur1->data > cur2->data){head = cur1;cur2 = cur2->next;head->next = NULL;tail = head;}else{head = cur1;cur1 = cur1->next;}head->next = NULL;tail = head;while (cur1 != NULL&&cur2 != NULL){if (cur1->data < cur2->data){tail->next = cur1;cur1 = cur1->next;}else{tail->next = cur2;cur2 = cur2->next;}tail->next->next = NULL;tail = tail->next;}if (cur1 == NULL){tail->next = cur2;}elsetail->next = cur1;return head;}PLinklist findmiddle(PLinklist pplist)//查找中间结点的元素{Node *slow = pplist;Node *quic = pplist;while (quic != NULL&&quic->next != NULL)//这里的顺序很重要不然就会越界程序崩溃{quic = quic->next->next;slow = slow->next;}return slow;}void deletk(PLinklist pplist, int k)//删除倒数第K个结点{Node *first = pplist;Node *second = pplist;while (first->next != NULL){if (--k <= 0){second = second->next;//指向删除的结点}first = first->next;}if (k <= 0){Node *src = second->next;second->data = second->next->data;second->next = second->next->next;//free(src);/*second->next->next = NULL;*/}}PLinklist checkcircle(PLinklist pplist)//判断一个链表是否带环{Node *slow = pplist;Node *fast = pplist;while (fast&&fast->next){fast = fast->next->next;slow = slow->next;if (fast == slow){return fast;}}return NULL;}int getcirclelong(PLinklist meet)//meet为入口点{Node *cur = meet;int count = 0;do{count++;cur=cur->next;} while (cur != meet);return count;}PLinklist findenterpoint(PLinklist pplist,PLinklist meet)//meet为相遇点点{Node *cur = pplist;while (meet != cur){meet = meet->next;cur = cur->next;}return meet;}PLinklist checklist(PLinklist pplist, PLinklist pplists)//判断两条链表是否相交,相交返回交点{Node *src = pplist;Node *dest = pplists;assert(pplist&&pplist);while (src->next != NULL){src = src->next;}while (dest ->next!= NULL){dest = dest->next;}if (src == dest)//相交了{Node *meet = NULL;src->next = pplists;//接成一个环meet = checkcircle(pplist);//找环指针的相遇地点Node *ret=findenterpoint(pplist, meet);//找环的入口点return ret;}else{return NULL;}}
最后给出test.c文件主要是测试函数和main函数

#define _CRT_SECURE_NO_WARNINGS 1#include"List.h"//void test2()//{//PLinklist head;//initList(&head);//int i = 0;//for (i = 1; i < 42; i++)//{//pushback(&head, i);//}//find_list(head, 41)->next = head;//josephcycle(head, 3);///*showlist(head);*///}void test(){PLinklist head;//定义头指针//PLinklist heads;//定义头指针initList(&head);//将头指初始化为空避免也指针的存在//initList(&heads);//将头指初始化为空避免也指针的存在,测试合并链表所定义的pushback(&head, 1);pushback(&head, 2);pushback(&head, 3);pushback(&head, 4);pushback(&head, 5);pushback(&head, 6);//pushback(&heads, 7);//pushback(&heads, 8);//pushback(&heads, 9);showlist(head);printf("\n");Node *ret = findmiddle(head);printf("%d", ret->data);//showlist(heads);//printf("\n");//find_list(heads, 9)->next = find_list(head, 5);//Node *ptr=checklist(head, heads);//printf("%d", ptr->data);//Node *src=checkcircle(head);//检查带不带环//printf("%d", src->data);//int ret=getcirclelong(src);//printf("%d", ret);//Node *dest=findenterpoint(head, src);//找入口点函数//printf("%d", dest->data);//showlist(head);//printf("\n");//deletk(head, 3);//pushback(&head, 8);//showlist(head);//printf("\n");//rever(&head);//showlist(findmiddle(head)->dtaa);//Node *x = findmiddle(head);//打印中间函数//printf("%d",x->data );//PLinklist pos=find_list(head, 4);//inertfrontnode(pos, 10);//test2();//delnotetail(pos);//bubble(head);/* printf("\n");*/ //showlist(Merge(&head, &heads));//showlist(heads);//_showlist(head);//逆序打印//destory(&head);//showlist(head);}int main(){test();system("pause");return 0;}
以上测试函数是我自己编写时按自己想法测试的,比较凌乱,你可以根据自己的想法去测试!

有什么问题欢迎留言一起交流学习!


原创粉丝点击