数据结构之_循环链表的实现与应用 约瑟夫环的问题
1.循环链表基本概念
2.循环链表设计与实现
- 插入元素分析
普通插入元素(和单链表是一样的)
- 尾插法(和单链表是一样的,单链表的写法支持尾插法
分析:最后一个结点的next指针指向新添加的结点,新结点的next指向第一个结点。
- 头插法
分析:
1.新节点指向当前的第一个结点
2.尾结点指向新节点
-
- 第一次插入结点
尾节点指针指向第一个数据节点(即自己指向自己)
- 删除结点分析
- 删除普通结点
-
- 删除头结点
更新head结点,并且尾结点重新连接新的头结点
3.循环链表案例代码
CircleLinkList.h
#ifndef CIRCLELINKLIST
#define CIRCLELINKLIST
#include<stdio.h>
#include<stdlib.h>
//链表的小结点
typedef struct CIRCLELINKNODE {
struct CIRCLELINKNODE* next;
}CircleLinkNode;
//链表结构体
typedef struct CIRCLELINKLIST {
CircleLinkNode head;
int size;
}CircleLinkList;
//编写针对链表结构体操作的API函数
#define CIRCLELINKLIST_TRUE 1
#define CIRCLELINKLIST_FALSE 0
//比较回调
typedef int(*COMPARENODE)(CircleLinkNode*, CircleLinkNode*);
//打印回调
typedef void(*PRINTNODE)(CircleLinkNode*);
//初始化函数
CircleLinkList* Init_CircleLinkList();
//插入函数
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data);
//获得第一个元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist);
//根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList* clist, int pos);
//根据值去删除
void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare);
//获得链表的长度
int Size_CircleLinkList(CircleLinkList* clist);
//判断是否为空
int IsEmpty_CircleLinkList(CircleLinkList* clist);
//查找
int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare);
//打印节点
void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print);
//释放内存
void FreeSpace_CircleLinkList(CircleLinkList* clist);
#endif
CircleLinkList.c
#include"CircleLinkList.h"
//初始化函数
CircleLinkList* Init_CircleLinkList() {
CircleLinkList* clist = (CircleLinkList*)malloc(sizeof(CircleLinkList));
clist->head.next = &(clist->head);
clist->size = 0;
return clist;
}
//插入函数
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data) {
if (clist == NULL) {
return;
}
if (data == NULL) {
return;
}
if (pos <0 || pos > clist->size) {
pos = clist->size;
}
//根据位置查找结点
//辅助指针变量
CircleLinkNode* pCurrent = &(clist->head);
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//新数据入链表
data->next = pCurrent->next;
pCurrent->next = data;
clist->size++;
}
//获得第一个元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist) {
return clist->head.next;
}
//根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList* clist, int pos) {
if (clist == NULL) {
return;
}
if (pos < 0 || pos >= clist->size) {
return;
}
//根据pos找结点
//辅助指针变量
CircleLinkNode* pCurrent = &(clist->head);
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//缓存当前结点的下一个结点
CircleLinkNode* pNext = pCurrent->next;
pCurrent->next = pNext->next;
clist->size--;
}
//根据值去删除
void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare) {
if (clist == NULL) {
return;
}
if (data == NULL) {
return;
}
//这个是循环链表
CircleLinkNode* pPrev = &(clist->head);
CircleLinkNode* pCurrent = pPrev->next;
int i = 0;
for (i = 0; i < clist->size; i++) {
if (compare(pCurrent, data) == CIRCLELINKLIST_TRUE) {
pPrev->next = pCurrent->next;
clist->size--;
break;
}
pPrev = pCurrent;
pCurrent = pPrev->next;
}
}
//获得链表的长度
int Size_CircleLinkList(CircleLinkList* clist) {
return clist->size;
}
//判断是否为空
int IsEmpty_CircleLinkList(CircleLinkList* clist) {
if (clist->size == 0) {
return CIRCLELINKLIST_TRUE;
}
return CIRCLELINKLIST_FALSE;
}
//查找
int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare) {
if (clist == NULL) {
return -1;
}
if (data == NULL) {
return -1;
}
CircleLinkNode* pCurrent = clist->head.next;
int flag = -1;
for (int i = 0; i < clist->size; i++) {
if (compare(pCurrent, data) == CIRCLELINKLIST_TRUE) {
flag = i;
break;
}
pCurrent = pCurrent->next;
}
return flag;
}
//打印节点
void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print) {
if (clist == NULL) {
return;
}
//辅助指针变量
CircleLinkNode* pCurrent = clist->head.next;
for (int i = 0; i < clist->size; i++) {
if (pCurrent == &(clist->head)) {
pCurrent = pCurrent->next;
printf("------------------\n");
}
print(pCurrent);
pCurrent = pCurrent->next;
}
}
//释放内存
void FreeSpace_CircleLinkList(CircleLinkList* clist) {
if (clist == NULL) {
return;
}
free(clist);
}
循环链表.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include"CircleLinkList.h"
typedef struct PERSON {
CircleLinkNode node;
char name[64];
int age;
int score;
}Person;
void MyPrint(CircleLinkNode* data) {
Person* p = (Person*)data;
printf("Name:%s Age:%d Score:%d\n", p->name, p->age, p->score);
}
int MyCompare(CircleLinkNode* data1, CircleLinkNode* data2) {
Person* p1 = (Person*)data1;
Person* p2 = (Person*)data2;
if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age&& p1->score == p2->score) {
return CIRCLELINKLIST_TRUE;
}
return CIRCLELINKLIST_FALSE;
}
int main(void) {
//创建循环链表
CircleLinkList* clist = Init_CircleLinkList();
//创建数据
Person p1, p2, p3, p4, p5;
strcpy(p1.name, "aaa");
strcpy(p2.name, "bbb");
strcpy(p3.name, "ccc");
strcpy(p4.name, "ddd");
strcpy(p5.name, "eee");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
p1.score = 50;
p2.score = 50;
p3.score = 60;
p4.score = 65;
p5.score = 70;
//数据入链表
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p1);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p2);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p3);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p4);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p5);
//打印
Print_CircleLinkList(clist, MyPrint);
Person pDel;
strcpy(pDel.name, "ddd");
pDel.age = 40;
pDel.score = 65;
//根据值删除
RemoveByValue_CircleLinkList(clist, (CircleLinkNode*)&pDel, MyCompare);
//打印
printf("--------------\n");
Print_CircleLinkList(clist, MyPrint);
//释放内存
FreeSpace_CircleLinkList(clist);
system("pause");
return 0;
}
4.循环链表应用(约瑟夫问题)
- 约瑟夫问题-循环链表典型应用
例题:n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,求出列顺序。
假设: m = 8,n=3
代码如下:
CircleLinkList.h
#ifndef CIRCLELINKLIST
#define CIRCLELINKLIST
#include<stdio.h>
#include<stdlib.h>
//链表的小结点
typedef struct CIRCLELINKNODE {
struct CIRCLELINKNODE* next;
}CircleLinkNode;
//链表结构体
typedef struct CIRCLELINKLIST {
CircleLinkNode head;
int size;
}CircleLinkList;
//编写针对链表结构体操作的API函数
#define CIRCLELINKLIST_TRUE 1
#define CIRCLELINKLIST_FALSE 0
//比较回调
typedef int(*COMPARENODE)(CircleLinkNode*, CircleLinkNode*);
//打印回调
typedef void(*PRINTNODE)(CircleLinkNode*);
//初始化函数
CircleLinkList* Init_CircleLinkList();
//插入函数
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data);
//获得第一个元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist);
//根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList* clist, int pos);
//根据值去删除
void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare);
//获得链表的长度
int Size_CircleLinkList(CircleLinkList* clist);
//判断是否为空
int IsEmpty_CircleLinkList(CircleLinkList* clist);
//查找
int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare);
//打印节点
void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print);
//释放内存
void FreeSpace_CircleLinkList(CircleLinkList* clist);
#endif
CircleLinkList.c
#include"CircleLinkList.h"
//初始化函数
CircleLinkList* Init_CircleLinkList() {
CircleLinkList* clist = (CircleLinkList*)malloc(sizeof(CircleLinkList));
clist->head.next = &(clist->head);
clist->size = 0;
return clist;
}
//插入函数
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data) {
if (clist == NULL) {
return;
}
if (data == NULL) {
return;
}
if (pos <0 || pos > clist->size) {
pos = clist->size;
}
//根据位置查找结点
//辅助指针变量
CircleLinkNode* pCurrent = &(clist->head);
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//新数据入链表
data->next = pCurrent->next;
pCurrent->next = data;
clist->size++;
}
//获得第一个元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist) {
return clist->head.next;
}
//根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList* clist, int pos) {
if (clist == NULL) {
return;
}
if (pos < 0 || pos >= clist->size) {
return;
}
//根据pos找结点
//辅助指针变量
CircleLinkNode* pCurrent = &(clist->head);
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//缓存当前结点的下一个结点
CircleLinkNode* pNext = pCurrent->next;
pCurrent->next = pNext->next;
clist->size--;
}
//根据值去删除
void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare) {
if (clist == NULL) {
return;
}
if (data == NULL) {
return;
}
//这个是循环链表
CircleLinkNode* pPrev = &(clist->head);
CircleLinkNode* pCurrent = pPrev->next;
int i = 0;
for (i = 0; i < clist->size; i++) {
if (compare(pCurrent, data) == CIRCLELINKLIST_TRUE) {
pPrev->next = pCurrent->next;
clist->size--;
break;
}
pPrev = pCurrent;
pCurrent = pPrev->next;
}
}
//获得链表的长度
int Size_CircleLinkList(CircleLinkList* clist) {
return clist->size;
}
//判断是否为空
int IsEmpty_CircleLinkList(CircleLinkList* clist) {
if (clist->size == 0) {
return CIRCLELINKLIST_TRUE;
}
return CIRCLELINKLIST_FALSE;
}
//查找
int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare) {
if (clist == NULL) {
return -1;
}
if (data == NULL) {
return -1;
}
CircleLinkNode* pCurrent = clist->head.next;
int flag = -1;
for (int i = 0; i < clist->size; i++) {
if (compare(pCurrent, data) == CIRCLELINKLIST_TRUE) {
flag = i;
break;
}
pCurrent = pCurrent->next;
}
return flag;
}
//打印节点
void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print) {
if (clist == NULL) {
return;
}
//辅助指针变量
CircleLinkNode* pCurrent = clist->head.next;
for (int i = 0; i < clist->size; i++) {
if (pCurrent == &(clist->head)) {
pCurrent = pCurrent->next;
printf("------------------\n");
}
print(pCurrent);
pCurrent = pCurrent->next;
}
}
//释放内存
void FreeSpace_CircleLinkList(CircleLinkList* clist) {
if (clist == NULL) {
return;
}
free(clist);
}
约瑟夫问题.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CircleLinkList.h"
#define M 8
#define N 3
typedef struct MYNUM {
CircleLinkNode node;
int val;
}MyNum;
void MyPrint(CircleLinkNode* data) {
MyNum* num = (MyNum*)data;
printf("%d ", num->val);
}
int MyCompare(CircleLinkNode* data1, CircleLinkNode* data2) {
MyNum* num1 = (MyNum*)data1;
MyNum* num2 = (MyNum*)data2;
if (num1->val == num2->val) {
return CIRCLELINKLIST_TRUE;
}
return CIRCLELINKLIST_FALSE;
}
int main(void) {
//创建循环链表
CircleLinkList* clist = Init_CircleLinkList();
//链表插入数据
MyNum num[M];
for (int i = 0; i < 8; i++) {
num[i].val = i + 1;
Insert_CircleLinkList(clist, i, (CircleLinkNode*)&num[i]);
}
//打印
Print_CircleLinkList(clist, MyPrint);
printf("\n");
int index = 1;
//辅助指针
CircleLinkNode* pCurrent = clist->head.next;
while (Size_CircleLinkList(clist) > 1) {
if (index == N) {
MyNum* temNum = (MyNum*)pCurrent;
printf("%d ", temNum->val);
//缓存待删除结点的下一个结点
CircleLinkNode* pNext = pCurrent->next;
//根据值删除
RemoveByValue_CircleLinkList(clist, pCurrent, MyCompare);
pCurrent = pNext;
if (pCurrent == &(clist->head)) {
pCurrent = pCurrent->next;
}
index = 1;
}
pCurrent = pCurrent->next;
if (pCurrent == &(clist->head)) {
pCurrent = pCurrent->next;
}
index++;
}
if (Size_CircleLinkList(clist) == 1) {
MyNum* tempNum = (MyNum*)Front_CircleLinkList(clist);
printf("%d ", tempNum->val);
}
else {
printf("出错!");
}
printf("\n");
//释放链表内存
FreeSpace_CircleLinkList(clist);
system("pause");
return 0;
}
5.优缺点分析
- 优点
- 功能增强了(循环链表只是在单链表的基础上做了一个加强)
- 循环链表可以完全取代单链表的使用
- 循环链表的Next和Current操作可以高效的遍历链表中的所有元素
- 缺点
- 代码复杂度提高了(成也萧何败萧何)