关于链表的基本操作以及常见操作大家可以移步
当然,链表除了这些基本操作之外,还有很多很有意思以及很有深度的问题,在这里,给大家介绍一些这方面的问题
- 逆序打印链表
- 不允许遍历链表,在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(LinkNode* 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->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, 如有纰漏,请斧正