关于链表的一些经典问题以及相关面试题
2018-04-01 10:33
405 查看
关于链表的基本操作以及常见操作大家可以移步
链表及相关函数实现
当然,链表除了这些基本操作之外,还有很多很有意思以及很有深度的问题,在这里,给大家介绍一些这方面的问题
逆序打印链表
不允许遍历链表,在pos节点前插入新节点
约瑟夫环问题求解
单链表逆置
单链表冒泡排序
将两个有序链表合并成一个有序链表
查找单链表的中间节点
寻找倒数第k个节点
删除倒数第k个节点
判断单链表是否带环,带环返回1
如果链表带环,返回环长度
如果单链表带环,求出环的入口
判定两个两个链表是否相交,若相交,返回交点,假设不带环
直接上代码
本文用例均实现在Centos 6.5, 如有纰漏,请斧正
链表及相关函数实现
当然,链表除了这些基本操作之外,还有很多很有意思以及很有深度的问题,在这里,给大家介绍一些这方面的问题
逆序打印链表
不允许遍历链表,在pos节点前插入新节点
约瑟夫环问题求解
单链表逆置
单链表冒泡排序
将两个有序链表合并成一个有序链表
查找单链表的中间节点
寻找倒数第k个节点
删除倒数第k个节点
判断单链表是否带环,带环返回1
如果链表带环,返回环长度
如果单链表带环,求出环的入口
判定两个两个链表是否相交,若相交,返回交点,假设不带环
直接上代码
Linklist.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define Datatype char typedef struct LinkNode { Datatype data; struct LinkNode* next; }LinkNode; //创建节点 LinkNode* Creat(); //销毁节点 void Destroy(LinkNode* node); //初始化节点 void LinklistInit(LinkNode** phead); //逆序打印链表 void LinklistReversePrint(LinkNode* head); //不允许遍历链表,在pos前插入节点 void LinklistInsertBefore(LinkNode* head, LinkNode* pos, Datatype value); //约瑟夫环 LinkNode* LinklistJosephCircle(LinkNode** phead, int step); //单链表逆置 void LinklistReverse(LinkNode** phead); void LinklistReverse2(LinkNode** phead); //单链表冒泡排序 void LinklistBubbleSort(Link 4000 Node* head); //将两个有序链表合并成一个有序链表 LinkNode* LinklistMerge(LinkNode* head1, LinkNode* head2); //查找单链表的中间节点 LinkNode* LinklistFindMidNode(LinkNode* head); //寻找倒数第k个节点 LinkNode* LinklistFindLastKNode(LinkNode* head, size_t k); //删除倒数第k个节点 void LinklistRemoveLastKNode(LinkNode** phead, size_t k); //判断单链表是否带环,带环返回1 int LinklistHasCircle(LinkNode* head); //如果链表带环,返回环长度 size_t LinklistGetCircleLength(LinkNode* head); //如果单链表带环,求出环的入口 LinkNode* LinklistEnter(LinkNode* head); //判定两个两个链表是否相交,若相交,返回交点,假设不带环 LinkNode* LinklistHasCross(LinkNode* head1, LinkNode* head2);
Linklist.c
#include "Linklist.h" //函数声明,因为大多数基本操作在文章刚开始的链接里实现过了,所以大多数基本操作都是直接实现,没有进行头文件声明 void LinklistPushback(LinkNode** phead, Datatype value); void LinklistPushfront(LinkNode** phead, Datatype value); //创建节点 LinkNode* Creat() { LinkNode* node = malloc(sizeof(LinkNode)); return node; } //销毁节点 void Destroy(LinkNode* node) { //非法输入 if(node == NULL) { perror("Destroy"); exit(1); } free(node); } //初始化节点 void LinklistInit(LinkNode** phead) { //非法输入 if(phead == NULL) { perror("Init"); exit(1); } *phead = NULL; } //逆序打印链表 void LinklistReversePrint(LinkNode* head) { //空链表 if(head == NULL) { printf("Empty linklist"); return; } LinkNode* cur = head; if(cur->next != NULL) { LinklistReversePrint(cur->next); } printf("%c\n", cur->data); } //不允许遍历链表,在pos前插入节点 void LinklistInsertBefore(LinkNode* head, LinkNode* pos, Datatype value) { //空链表 if(head == NULL) { return; } //创建新节点 LinkNode* node = Creat(); node->data = pos->data; node->next = pos->next; pos->next = node; pos->data = value; } //约瑟夫环 LinkNode* LinklistJosephCircle(LinkNode** phead, int step) { //非法输入 if(phead == NULL) { perror("JosephCircle"); exit(1); } //空链表 if(*phead == NULL) { return; } LinkNode* cur = *phead; LinkNode* pre = *phead; while(cur->next != cur) { int count = step; while(count--) { pre = cur; cur = cur->next; } LinkNode* tmp = cur; printf("remove %c\n", tmp->data); pre->next = cur->next; cur = pre->next; Destroy(tmp); } return cur; } //单链表逆置 /* 1.头插 定义一个指针cur指向当前节点,定义一个指针tmp分离cur指向的当前节点,然后cur后移,将tmp->next指向phead,然后将phead指向tmp 2.就地逆置 定义两个指针cur,pre,第一次cur跳过phead,每次将cur->next指向pre,然后一直后移cur,pre,最后将phead->next = NULL,phead指向pre */ void LinklistReverse(LinkNode** phead) { //非法输入 if(phead == NULL) { perror("reverse"); exit(1); } //空链表 if(*phead == NULL) { return; } //一个节点 if((*phead)->next == NULL) { return; } LinkNode* cur = *phead; cur = cur->next; (*phead)->next = NULL; while(cur != NULL) { LinkNode* tmp = cur; cur = cur->next; tmp->next = *phead; *phead = tmp; } } void LinklistReverse2(LinkNode** phead) { //非法输入 if(phead == NULL) { perror("reverse2"); exit(1); } //空链表 if(*phead == NULL) { return; } //一个节点 if((*phead)->next == NULL) { return; } LinkNode* pre = *phead; LinkNode* cur = (*phead)->next; while(cur != NULL) { LinkNode* tmp = cur->next; cur->next = pre; pre = cur; cur = tmp; } (*phead)->next = NULL; *phead = pre; } //单链表冒泡排序 void LinklistBubbleSort(LinkNode* head) { //非法输入 if(head == NULL) { return; } //一个节点 if(head->next == NULL) { return; } LinkNode* cur = head; LinkNode* next = head; int count = 0; while(cur != NULL) { cur = cur->next; count++; } int i; for(i=0; i<count; i++) { int j; for(j=0; j<count-1-i; j++) { cur = next; next = next->next; if(cur->data > next->data) { Datatype tmp = cur->data; cur->data = next->data; next->data = tmp; } } cur = next = head; } } //将两个有序链表合并成一个有序链表 LinkNode* LinklistMerge(LinkNode* head1, LinkNode* head2) { //第一个链表为空链表,若两个都为空,返回head2相当于返回空 if(head1 == NULL) { return head2; } //第二个链表为空链表 if(head2 == NULL) { return head1; } //创建新链表 LinkNode* head = Creat(); LinklistInit(&head); LinkNode* cur1 = head1; LinkNode* cur2 = head2; while(cur1!=NULL && cur2!=NULL) { if(cur1->data >= cur2->data) { LinklistPushback(&head, cur2->data); LinkNode* tmp = cur2; cur2 = cur2->next; Destroy(tmp); }else { LinklistPushback(&head, cur1-&g 13471 t;data); LinkNode* tmp = cur1; cur1 = cur1->next; Destroy(tmp); } } //得到最后一个节点 LinkNode* end = head; while(end->next != NULL) { end = end->next; } if(cur2 != NULL) { end->next = cur2; } if(cur1 != NULL) { end->next = cur1; } return head; } //查找单链表的中间节点 LinkNode* LinklistFindMidNode(LinkNode* head) { //非法输入 if(head == NULL) { return NULL; } //一个节点 if(head->next == NULL) { return head; } LinkNode* fast = head; LinkNode* slow = head; while(fast->next!=NULL && fast->next->next!=NULL) { fast = fast->next->next; slow = slow->next; } return slow; } //寻找倒数第k个节点 LinkNode* LinklistFindLastKNode(LinkNode* head, size_t k) { //非法输入 if(head == NULL) { return NULL; } LinkNode* fast = head; LinkNode* slow = head; while(k--){ if(fast == NULL) { return NULL; } fast = fast->next; } while(fast != NULL) { fast = fast->next; slow = slow->next; } return slow; } //删除倒数第k个节点 void LinklistRemoveLastKNode(LinkNode** phead, size_t k) { //非法输入 if(phead == NULL) { perror("RemoveLastKNode"); exit(1); } //链表为空 if((*phead) == NULL) { return; } LinkNode* to_remove = LinklistFindLastKNode(*phead, k); //得到了删除节点 //1.节点是最后一个,得遍历到前一个 if(to_remove->next == NULL) { LinkNode* cur = *phead; while(cur->next != to_remove) { cur = cur->next; } cur->next = NULL; Destroy(to_remove); return; } //2.节点是第一个和普通个,偷天换日 LinkNode* tmp = to_remove->next; to_remove->data = tmp->data; to_remove->next = tmp->next; Destroy(tmp); } //判断单链表是否带环,带环返回1 int LinklistHasCircle(LinkNode* head) { //空链表 if(head == NULL) { return 0; } LinkNode* fast = head->next; LinkNode* slow = head; while(fast!=slow && fast->next!=NULL && fast->next->next!=NULL ) { fast = fast->next->next; slow = slow->next; } if(fast == slow) { return 1; }else { return 0; } } //如果链表带环,返回环长度 size_t LinklistGetCircleLength(LinkNode* head) { //空链表 if(head == NULL) { return 0; } //如果链表带环 int flag = LinklistHasCircle(head); if(flag == 1) { printf("Linklist has circle, can not count\n"); return -1; } LinkNode* cur = head; size_t count = 0; while(cur != NULL) { cur = cur->next; count++; } return count; } //如果单链表带环,求出环的入口 LinkNode* LinklistEnter(LinkNode* head) { //空链表 if(head == NULL) { return 0; } LinkNode* fast = head->next; LinkNode* slow = head; while(fast != slow) { fast = fast->next->next; slow = slow->next; } //相遇点 LinkNode* MeetNode = fast; LinkNode* step = head; while(step == MeetNode) { step = step->next; MeetNode = MeetNode->next; } return step; } //判定两个两个链表是否相交,若相交,返回交点,假设不带环 LinkNode* LinklistHasCross(LinkNode* head1, LinkNode* head2) { //链表为空 if(head1 == NULL) { perror("Has cross head1 is NULL\n"); return NULL; } if(head2 == NULL) { perror("Has cross head1 is NULL\n"); return NULL; } //两个链表相同 if(head1 == head2) { return head1; } size_t len1 = 0; size_t len2 = 0; LinkNode* cur1 = head1; LinkNode* cur2 = head2; while(cur1 != NULL) { cur1 = cur1->next; len1++; } while(cur2 != NULL) { cur2 = cur2->next; len2++; } //相交 if(cur2 == cur1) { cur1 = head1; cur2 = head2; if(len1 > len2) { int count = len1-len2; while(count--) { cur1 = cur1->next; } while(cur1 != cur2) { cur1 = cur1->next; cur2 = cur2->next; } return cur2; } else { int count = len2-len1; while(count--) { cur2 = cur2->next; } while(cur1 != cur2) { cur1 = cur1->next; cur2 = cur2->next; } return cur2; } } else { return NULL; } } /************************************************ ****************** Test ********************** ************************************************/ #define FUNCTION() printf("=================================== %s ===================================\n",\ __FUNCTION__ ) /************************************************ ****************** 辅助单元 ********************* ************************************************/ //链表尾插 void LinklistPushback(LinkNode** phead, Datatype value) { //非法输入 if(phead == NULL) { perror("LinklistPushback"); return; } //空链表 if(*phead == NULL) { *phead = Creat(); (*phead)->data = value; (*phead)->next = NULL; return; } //创建新节点 LinkNode* new = Creat(); new->data = value; new->next = NULL; LinkNode* cur = *phead; while(cur->next != NULL) { cur = cur->next; } cur->next = new; return; } //链表头插 void LinklistPushfront(LinkNode** phead, Datatype value) { //输入空指针 if(phead == NULL) { perror("LinklistPushfront"); return; } //创建新节点 LinkNode* node = Creat(); LinkNode* cur = *phead; node->data = value; *phead = node; node->next = cur; } void printChar(LinkNode* head, const char* msg) { //空链表 if(head == NULL) { printf("Empty linklist"); return; } printf("%s \n", msg); LinkNode* cur = head; while(cur != NULL) { printf("[%c | %p ] ", cur->data, cur); cur = cur->next; } printf("\n"); } /********* *测试单元 *********/ //逆序打印链表测试 void TestReversePrint() { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); //printChar(head, "haha"); LinklistReversePrint(head); } //不遍历链表在pos前插入 void TestInsertBefore() { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); printChar(head,"before test"); LinklistInsertBefore(head, head, 'x'); printChar(head,"insert before a"); } //约瑟夫环测试 void TestJosephCircle() { FUNCTION(); LinkNode* head; LinklistInit(&head); //构建一个四个元素的环 LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); head->next->next->next->next = head; LinkNode* ret = LinklistJosephCircle(&head, 5); printf("%c\n", ret->data); } //头插逆置测试 void TestReverse(void) { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); printChar(head,"before test"); LinklistReverse(&head); printChar(head,"reverse"); } //就地逆置测试 void TestReverse2(void) { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); printChar(head,"before test"); LinklistReverse2(&head); printChar(head,"reverse2"); } //冒泡排序测试 void TestBubbleSort() { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'g'); LinklistPushback(&head, 'r'); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'g'); LinklistPushback(&head, 'l'); LinklistPushback(&head, 'e'); LinklistPushback(&head, 'v'); LinklistPushback(&head, 't'); printChar(head,"before test"); LinklistBubbleSort(head); printChar(head,"before test"); } //把两个有序量表拼成一个有序链表测试 void TestMerge() { FUNCTION(); LinkNode* head1; LinklistInit(&head1); LinklistPushback(&head1, 'a'); LinklistPushback(&head1, 'b'); LinklistPushback(&head1, 'c'); LinklistPushback(&head1, 'd'); printChar(head1,"before test"); LinkNode* head2; LinklistInit(&head2); LinklistPushback(&head2, 'a'); LinklistPushback(&head2, 'b'); LinklistPushback(&head2, 'c'); LinklistPushback(&head2, 'd'); printChar(head2,"before test"); LinkNode* head = LinklistMerge(head1, head2); printChar(head, "after merge"); } //寻找中间节点测试 void TestFindMidNode() { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); LinklistPushback(&head, 'e'); printChar(head,"before test"); LinkNode* ret = LinklistFindMidNode(head); printf("%c\n", ret->data); } //寻找倒数第k个节点测试 void TestFindLastKNode() { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); LinklistPushback(&head, 'e'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); LinklistPushback(&head, 'e'); printChar(head,"before test"); LinkNode* ret = LinklistFindLastKNode(head, 1); printf("%c\n", ret->data); } //删除倒数第k个节点测试 void TestRemoveLastKNode() { FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); LinklistPushback(&head, 'e'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); LinklistPushback(&head, 'e'); printChar(head,"before test"); LinklistRemoveLastKNode(&head, 1); printChar(head, "remove last 1"); } //判断链表是否带环测试 void TestHasCircle() { FUNCTION(); LinkNode* head; LinklistInit(&head); //构建一个两元素的环 LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); //LinklistPushback(&head, 'c'); //LinklistPushback(&head, 'd'); // head->next->next = head; int ret = LinklistHasCircle(head); if(ret == 1) { printf("带环\n"); }else { printf("不带环\n"); } } //链表长度测试 void TestGetCircleLength() { FUNCTION(); LinkNode* head; LinklistInit(&head); // LinklistPushback(&head, 'a'); // LinklistPushback(&head, 'a'); // LinklistPushback(&head, 'b'); // LinklistPushback(&head, 'c'); // LinklistPushback(&head, 'd'); // LinklistPushback(&head, 'e'); // LinklistPushback(&head, 'b'); // LinklistPushback(&head, 'c'); // LinklistPushback(&head, 'd'); // LinklistPushback(&head, 'e'); // printChar(head,"before test"); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); head->next->next->next->next = head; size_t ret = LinklistGetCircleLength(head); printf("The linklist length is %d\n", ret); } //环入口点测试 void TestEnter() { //构建四元环 FUNCTION(); LinkNode* head; LinklistInit(&head); LinklistPushback(&head, 'a'); LinklistPushback(&head, 'b'); LinklistPushback(&head, 'c'); LinklistPushback(&head, 'd'); head->next->next->next->next = head; LinkNode* ret = LinklistEnter(head); printf("The actual enter address is %p, function return address is %p\n", head, ret); } //判定两个两个链表是否相交(假设不带环)测试 void TestHasCross() { FUNCTION(); LinkNode* head1; LinklistInit(&head1); LinklistPushback(&head1, 'a'); LinklistPushback(&head1, 'b'); LinklistPushback(&head1, 'c'); LinkNode* head2; LinklistInit(&head2); LinklistPushback(&head2, 'a'); LinklistPushback(&head2, 'b'); LinkNode* head3; LinklistInit(&head3); LinklistPushback(&head3, 'a'); LinklistPushback(&head3, 'b'); LinklistPushback(&head3, 'c'); LinklistPushback(&head3, 'd'); //创建相交点 head1->next->next->next = head3; head2->next->next = head3; printChar(head1,"head1"); printChar(head2,"head2"); LinkNode*ret = LinklistHasCross(head1, head2); printf("The actual meet node address is %p, function return address is %p\n", head3, ret); } int main() { TestReversePrint(); TestInsertBefore(); TestJosephCircle(); TestReverse(); TestReverse2(); TestBubbleSort(); TestMerge(); TestFindMidNode(); TestFindLastKNode(); TestRemoveLastKNode(); TestHasCircle(); TestGetCircleLength(); TestEnter(); TestHasCross(); }
本文用例均实现在Centos 6.5, 如有纰漏,请斧正
相关文章推荐
- Axure RP Pro - 相关问题 - Style Editor样式编辑器以及已知的一些缺陷
- VC++学习笔记(3)------- CString相关的一些问题以及LineLength()的
- 关于FAT32和NTFS文件系统的介绍以及相关问题的解答(转自“第二战区”)
- 【主题】关于做代码以及文档review的一些问题
- 关于ORACLE的ora-12505报错以及连接问题的解决及相关资料
- 关于ORACLE的ora-12505报错以及连接问题的解决及相关资料
- 经典面试题:链表的相交与环问题
- 数据结构学习笔记 --- 线性表 (一些常见的关于链表的算法和面试题)
- 关于一些core dump的问题,makefile以及gdb的使用问题
- 【每日面试题】链表相关问题1
- 经典面试题:链表的相交与环问题
- 关于ORACLE的ora-12505报错以及连接问题的解决及相关资料
- 一道经典的关于Fibonacci数列的面试题(问题)的新想法 -> N阶楼梯问题
- 转帖:关于链表操作不得不看的经典问题
- 关于ORACLE的ora-12505报错以及连接问题的解决及相关资料
- 关于Eclipse3.3中内容助手不是Alt+/的问题解答,以及它的一些其他新特性
- 关于ORACLE的ora-12505报错以及连接问题的解决及相关资料
- 关于链表的一些问题
- 关于ORACLE的ora-12505报错以及连接问题的解决及相关资料