您的位置:首页 > 职场人生

关于链表的一些经典问题以及相关面试题

2018-04-01 10:33 405 查看
关于链表的基本操作以及常见操作大家可以移步

链表及相关函数实现

当然,链表除了这些基本操作之外,还有很多很有意思以及很有深度的问题,在这里,给大家介绍一些这方面的问题

逆序打印链表

不允许遍历链表,在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, 如有纰漏,请斧正
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: