双向链表
1、概念
1)就是从任意一个节点既能存储其前驱节点,又能存储后继节点
2)结构体中增加一个指向前驱节点的指针
//定义数据类型
typedef int datatype;
//定义节点类型
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *prio;
struct Node *next;
};
3)头节点没有前驱,最后一个节点没有后继
2、创建虚拟链表
// 创建链表
NodePtr list_create()
{
// 在堆区申请一个头节点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if (NULL == L)
{
printf("创建失败\n");
return NULL;
}
L->len = 0;
L->next = NULL;
L->prio = NULL;
printf("链表创建成功\n");
return L;
}
3、申请封装数据
// 申请封装数据
NodePtr apply_node(datatype e)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if (NULL == p)
{
printf("数据类型不合法,封装失败\n");
return NULL;
}
p->data = e;
p->prio = NULL;
p->next = NULL;
return p;
}
4、判空
// 判空
int list_empty(NodePtr L)
{
return L->next == NULL;
}
5、头插
// 头插
int list_insert_head(NodePtr L, datatype e)
{
if (NULL == L)
{
printf("数据类型不合法,头插失败\n");
return -1;
}
NodePtr p = apply_node(e);
if (NULL == p)
{
printf("数据封装失败,头插失败\n");
return -1;
}
if (list_empty(L))
{
p->prio = L;
L->next = p;
}
else
{
p->prio = L;
p->next = L->next;
L->next->prio = p; // p->next->prio =p;
L->next = p;
}
L->len++;
printf("插入成功\n");
return 0;
}
6、链表遍历
// 链表遍历
int list_show(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr q = L->next; // 定义遍历指针从第一个节点出发
while (q)
{
// 输出数据域
printf("%c", q->data);
q = q->next; // 指针指向下一数据域
}
putchar(10);
printf("遍历结束\n");
}
7、按完整查找
// 按位置查找
NodePtr list_search_pos(NodePtr L,datatype pos)
{
if (NULL == L || list_empty(L) || pos > L->len || pos < 0)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for(int i = 0;i < pos ; i++)
{
q = q->next;
}
printf("查找成功\n");
return q;
}
8、按位置删除
// 按位置删除
int list_delete_pos(NodePtr L,datatype pos)
{
if (NULL == L || list_empty(L) || pos < 1 || pos > L->len)
{
printf("按位置删除失败\n");
return -1;
}
NodePtr q = list_search_pos(L,pos);
if (q->next == NULL)
{
q->prio->next = NULL;
}
else
{
// q->next->prio = q->prio;
// q->next->prio->next = q->next;
q->prio->next = q->next;
q->next->prio = q->prio;
}
L->len--;
free(q);
q = NULL;
printf("删除成功\n");
return 0;
}
9、链表删除
// 链表删除
void list_destroy(NodePtr L)
{
if (NULL == L )
{
printf("删除失败\n");
return;
}
while (L->next/*!(list_empty(L))*/)
{
list_delete_pos(L,1);
}
if (L->next = NULL)
{
free(L);
L->next = NULL;
}
printf("删除成功\n");
return ;
}
10、完整代码
00.h
#ifndef day16_flag_h
#define day16_flag_h
#include <myhead.h>
typedef char datatype;
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *prio;
struct Node *next;
}Node,*NodePtr;
NodePtr list_create();
int list_empty(NodePtr L);
NodePtr apply_node(datatype e);
int list_insert_head(NodePtr l,datatype e);
int list_show(NodePtr L);
int list_search(NodePtr L,datatype pos);
int list_delete_pos(NodePtr L,datatype e);
void list_destroy(NodePtr L);
#endif // day16_flag_h
00.c
#include "00.h"
#define MAX 50
// 创建链表
NodePtr list_create()
{
// 在堆区申请一个头节点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if (NULL == L)
{
printf("创建失败\n");
return NULL;
}
L->len = 0;
L->next = NULL;
L->prio = NULL;
printf("链表创建成功\n");
return L;
}
// 判空
int list_empty(NodePtr L)
{
return L->next == NULL;
}
// 申请封装数据
NodePtr apply_node(datatype e)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if (NULL == p)
{
printf("数据类型不合法,封装失败\n");
return NULL;
}
p->data = e;
p->prio = NULL;
p->next = NULL;
return p;
}
// 头插
int list_insert_head(NodePtr L, datatype e)
{
if (NULL == L)
{
printf("数据类型不合法,头插失败\n");
return -1;
}
NodePtr p = apply_node(e);
if (NULL == p)
{
printf("数据封装失败,头插失败\n");
return -1;
}
if (list_empty(L))
{
p->prio = L;
L->next = p;
}
else
{
p->prio = L;
p->next = L->next;
L->next->prio = p; // p->next->prio =p;
L->next = p;
}
L->len++;
printf("插入成功\n");
return 0;
}
// 链表遍历
int list_show(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr q = L->next; // 定义遍历指针从第一个节点出发
while (q)
{
// 输出数据域
printf("%c", q->data);
q = q->next; // 指针指向下一数据域
}
putchar(10);
printf("遍历结束\n");
}
// 按位置查找
NodePtr list_search_pos(NodePtr L,datatype pos)
{
if (NULL == L || list_empty(L) || pos > L->len || pos < 0)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for(int i = 0;i < pos ; i++)
{
q = q->next;
}
printf("查找成功\n");
return q;
}
// 按位置删除
int list_delete_pos(NodePtr L,datatype pos)
{
if (NULL == L || list_empty(L) || pos < 1 || pos > L->len)
{
printf("按位置删除失败\n");
return -1;
}
NodePtr q = list_search_pos(L,pos);
if (q->next == NULL)
{
q->prio->next = NULL;
}
else
{
// q->next->prio = q->prio;
// q->next->prio->next = q->next;
q->prio->next = q->next;
q->next->prio = q->prio;
}
L->len--;
free(q);
q = NULL;
printf("删除成功\n");
return 0;
}
// 链表删除
void list_destroy(NodePtr L)
{
if (NULL == L )
{
printf("删除失败\n");
return;
}
while (L->next/*!(list_empty(L))*/)
{
list_delete_pos(L,1);
}
if (L->next = NULL)
{
free(L);
L->next = NULL;
}
printf("删除成功\n");
return ;
}
00main.c
#include "00.h"
int main(int argc, char const *argv[])
{
NodePtr L = list_create();
if (NULL == L )
{
return -1;
}
list_insert_head(L,'H');
list_show(L);
list_insert_head(L,'e');
list_show(L);
list_insert_head(L,'l');
list_show(L);
list_insert_head(L,'l');
list_show(L);
list_insert_head(L,'o');
list_show(L);
list_delete_pos(L,1);
list_show(L);
list_delete_pos(L,2);
list_show(L);
list_delete_pos(L,L->len);
list_show(L);
list_destroy(L);
list_show(L);
return 0;
}
单向循环链表
1、概念
1)循环链表,就是首尾相接的链表
2)循环链表,就是首尾相接的链表
3)双向循环链表:需要将最后一个阶段的指针域指向头结点,头结点的前驱指针指向最后一 个阶段
2、循环链表的创建
1)创建虚拟链表
// 创建链表
NodePtr list_create()
{
// 在堆区申请一个头节点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if (NULL == L)
{
printf("创建失败\n");
return NULL;
}
L->len = 0;
L->next = NULL;
L->prio = NULL;
printf("链表创建成功\n");
return L;
}
2)判空
// 判空
int list_empty(NodePtr L)
{
return L->next == L;
}
3)申请封装数据
// 申请封装数据
NodePtr apply_node(datatype e)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if (NULL == p)
{
printf("数据类型不合法,封装失败\n");
return NULL;
}
p->data = e;
p->next = NULL;
return p;
}
4)按位置查找
// 按位置查找
NodePtr list_search_pos(NodePtr L, datatype pos)
{
if (NULL == L || list_empty(L) || pos > L->len || pos < 0)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for (int i = 0; i < pos; i++)
{
q = q->next;
}
printf("查找成功\n");
return q;
}
5)头插
// 头插
int list_insert_head(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("插入失败\n");
return -1;
}
NodePtr p = apply_node(e);
if (NULL == p)
{
printf("封装失败\n");
return -1;
}
p->next = L->next;
L->next = p;
L->len++;
printf("插入成功\n");
return 0;
}
6)尾插
// 尾插
int list_insert_tail(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("尾插插入失败\n");
return -1;
}
// 找到最后一个节点
NodePtr q = list_search_pos(L, L->len);
// 封装节点
NodePtr p = apply_node(e);
// 插入逻辑
p->next = q->next;
q->next = p;
L->len++;
printf("尾插插入成功\n");
return 0;
}
7)头删
//头删
int list_delete_head(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("头删失败\n");
return -1;
}
NodePtr p = L->next;
L->next = p->next;
free(p);
p = NULL;
L->len--;
printf("头删成功\n");
return 0;
}
8)链表删除
// 链表删除
void list_destroy(NodePtr L)
{
if (NULL == L )
{
printf("删除失败\n");
return;
}
while (L->next == L)
{
list_delete_head(L);
}
free(L);
L = NULL;
printf("删除成功\n");
return ;
}
9)完整代码
00.h
#ifndef day16_1_flag_h
#define day16_1_flag_h
#include <myhead.h>
typedef char datatype;
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *next;
}Node,*NodePtr;
NodePtr list_create();
int list_empty(NodePtr L);
NodePtr apply_node(datatype e);
NodePtr list_search_pos(NodePtr L,datatype pos);
int list_insert_tail(NodePtr L,datatype e);
int list_insert_head(NodePtr L,datatype e);
int list_show(NodePtr L);
int list_delete_head(NodePtr L);
void list_destroy(NodePtr L);
#endif // day16_1_flag_h
00.c
#include "00.h"
#define MAX 50
// 创建链表
NodePtr list_create()
{
// 在堆区申请一个头节点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if (NULL == L)
{
printf("创建失败\n");
return NULL;
}
L->len = 0;
L->next = L; // 头节点指针域指向自己
printf("链表创建成功\n");
return L;
}
// 判空
int list_empty(NodePtr L)
{
return L->next == L;
}
// 申请封装数据
NodePtr apply_node(datatype e)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if (NULL == p)
{
printf("数据类型不合法,封装失败\n");
return NULL;
}
p->data = e;
p->next = NULL;
return p;
}
// 按位置查找
NodePtr list_search_pos(NodePtr L, datatype pos)
{
if (NULL == L || list_empty(L) || pos > L->len || pos < 0)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for (int i = 0; i < pos; i++)
{
q = q->next;
}
printf("查找成功\n");
return q;
}
// 头插
int list_insert_head(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("插入失败\n");
return -1;
}
NodePtr p = apply_node(e);
if (NULL == p)
{
printf("封装失败\n");
return -1;
}
p->next = L->next;
L->next = p;
L->len++;
printf("插入成功\n");
return 0;
}
// 尾插
int list_insert_tail(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("尾插插入失败\n");
return -1;
}
// 找到最后一个节点
NodePtr q = list_search_pos(L, L->len);
// 封装节点
NodePtr p = apply_node(e);
// 插入逻辑
p->next = q->next;
q->next = p;
L->len++;
printf("尾插插入成功\n");
return 0;
}
//链表遍历
int list_show(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr q = L->next;
while(q !=L)
{
printf("%c",q->data);
q = q->next;
}
putchar(10);
printf("遍历成功\n");
return 0;
}
//头删
int list_delete_head(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("头删失败\n");
return -1;
}
NodePtr p = L->next;
L->next = p->next;
free(p);
p = NULL;
L->len--;
printf("头删成功\n");
return 0;
}
// 链表删除
void list_destroy(NodePtr L)
{
if (NULL == L )
{
printf("删除失败\n");
return;
}
while (L->next == L)
{
list_delete_head(L);
}
free(L);
L = NULL;
printf("删除成功\n");
return ;
}
00main.c
#include "00.h"
int main(int argc, char const *argv[])
{
NodePtr L = list_create();
if (NULL == L )
{
return -1;
}
list_insert_head(L,'H');
list_show(L);
list_insert_head(L,'e');
list_show(L);
list_insert_head(L,'l');
list_show(L);
list_insert_head(L,'l');
list_show(L);
list_insert_head(L,'o');
list_show(L);
list_insert_tail(L,'Z');
list_show(L);
list_delete_head(L);
list_show(L);
list_destroy(L);
list_show(L);
return 0;
}
10)约瑟夫环问题
00.h
#ifndef day16_1_flag_h
#define day16_1_flag_h
#include <myhead.h>
typedef int datatype;
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *next;
}Node,*NodePtr;
NodePtr list_create();
int list_empty(NodePtr L);
NodePtr apply_node(datatype e);
NodePtr list_search_pos(NodePtr L,datatype pos);
int list_insert_tail(NodePtr L,datatype e);
int list_insert_head(NodePtr L,datatype e);
int list_show(NodePtr L);
int list_delete_head(NodePtr L);
void list_destroy(NodePtr L);
// 任意位置删除
int list_delete_pos(NodePtr L, int pos);
//按位置取值
int list_pos_value(NodePtr L,int pos);
#endif // day16_1_flag_h
00.c
#include "00.h"
#define MAX 50
// 创建链表
NodePtr list_create()
{
// 在堆区申请一个头节点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if (NULL == L)
{
printf("创建失败\n");
return NULL;
}
L->len = 0;
L->next = L; // 头节点指针域指向自己
printf("链表创建成功\n");
return L;
}
// 判空
int list_empty(NodePtr L)
{
return L->next == L;
}
// 申请封装数据
NodePtr apply_node(datatype e)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if (NULL == p)
{
printf("数据类型不合法,封装失败\n");
return NULL;
}
p->data = e;
p->next = NULL;
return p;
}
// 按位置查找
NodePtr list_search_pos(NodePtr L, datatype pos)
{
if (NULL == L || list_empty(L) || pos > L->len || pos < 0)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for (int i = 0; i < pos; i++)
{
q = q->next;
}
printf("查找成功\n");
return q;
}
// 头插
int list_insert_head(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("插入失败\n");
return -1;
}
NodePtr p = apply_node(e);
if (NULL == p)
{
printf("封装失败\n");
return -1;
}
p->next = L->next;
L->next = p;
L->len++;
printf("插入成功\n");
return 0;
}
// 尾插
int list_insert_tail(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("尾插插入失败\n");
return -1;
}
// 找到最后一个节点
NodePtr q = list_search_pos(L, L->len);
// 封装节点
NodePtr p = apply_node(e);
// 插入逻辑
p->next = q->next;
q->next = p;
L->len++;
printf("尾插插入成功\n");
return 0;
}
//链表遍历
int list_show(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr q = L->next;
while(q !=L)
{
printf("%d\t",q->data);
q = q->next;
}
putchar(10);
printf("遍历成功\n");
return 0;
}
//头删
int list_delete_head(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("头删失败\n");
return -1;
}
NodePtr p = L->next;
L->next = p->next;
free(p);
p = NULL;
L->len--;
printf("头删成功\n");
return 0;
}
// 链表删除
void list_destroy(NodePtr L)
{
if (NULL == L )
{
printf("删除失败\n");
return;
}
while (L->next == L)
{
list_delete_head(L);
}
free(L);
L = NULL;
printf("删除成功\n");
return ;
}
// 任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
if (NULL == L || pos > L->len + 1 || pos < 1)
{
printf("删除失败\n");
return -1;
}
NodePtr q = list_search_pos(L, pos - 1);
NodePtr p = q->next;
q->next = p->next;
free(p);
p = NULL;
L->len--;
printf("删除成功\n");
return 0;
}
00main.c
#include "00.h"
int main(int argc, char const *argv[])
{
//创建列表
NodePtr L = list_create();
if (NULL == L)
{
return -1;
}
//num 人数 die 死亡序号
int num, die = 0;
printf("输入参与约瑟夫游戏的人数:\n");
scanf("%d", &num);
printf("报数到多少被杀掉:\n");
scanf("%d", &die);
//为参与者赋予代号
for (int i = 0; i < num; i++)
{
list_insert_head(L, i+1);
}
list_show(L);
//day 日期 all 总人数 death 死者数组
int day = 0;
int all = num;
datatype death[100] = {0}; //死者序列
NodePtr p = L;
while (num>all/2)
{
for (int i = 0; i < die-1; i++)
{
if (p->next == L)//到头节点时多偏移一位,略过头节点
{
p = p->next;
}
p = p->next;
}
int kill = p->next->data; //死者代号
death[day] = kill; //将死者代号存入死者名列
printf("%d\n",kill);
list_delete_head(p->next); //删除死者位置
day++; //日期推移
num--; //人数减一
}
printf("死者代号及顺序依次为:\n");
for (int i = 0; i < day; i++)
{
printf("%d\t", death[i]);
}
putchar(10);
return 0;
}
双向循环链表
00.h
#ifndef day16_1_flag_h
#define day16_1_flag_h
#include <myhead.h>
typedef char datatype;
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *next;
struct Node *prio;
}Node,*NodePtr;
NodePtr list_create();
int list_empty(NodePtr L);
NodePtr apply_node(datatype e);
NodePtr list_search_pos(NodePtr L,datatype pos);
int list_insert_tail(NodePtr L,datatype e);
int list_insert_head(NodePtr L,datatype e);
int list_show(NodePtr L);
int list_delete_head(NodePtr L);
void list_destroy(NodePtr L);
// 任意位置删除
int list_delete_pos(NodePtr L, int pos);
//按位置取值
int list_pos_value(NodePtr L,int pos);
//按位置修改
int list_change_pos(NodePtr L,int pos,datatype e);
#endif // day16_1_flag_h
00.c
#include "00.h"
#define MAX 50
// 创建链表
NodePtr list_create()
{
// 在堆区申请一个头节点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if (NULL == L)
{
printf("创建失败\n");
return NULL;
}
L->len = 0;
L->next = L; // 头节点指针域指向自己
L->prio = L;
printf("链表创建成功\n");
return L;
}
// 判空
int list_empty(NodePtr L)
{
return L->next == L;
}
// 申请封装数据
NodePtr apply_node(datatype e)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if (NULL == p)
{
printf("数据类型不合法,封装失败\n");
return NULL;
}
p->data = e;
p->next = NULL;
p->prio = NULL;
return p;
}
// 按位置查找
NodePtr list_search_pos(NodePtr L, datatype pos)
{
if (NULL == L || list_empty(L) || pos > L->len || pos < 0)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for (int i = 0; i < pos; i++)
{
q = q->next;
}
printf("查找成功\n");
return q;
}
// 头插
int list_insert_head(NodePtr L, datatype e)
{
if (NULL == L)
{
printf("数据类型不合法,头插失败\n");
return -1;
}
NodePtr p = apply_node(e);
if (NULL == p)
{
printf("数据封装失败,头插失败\n");
return -1;
}
if (list_empty(L))
{
p->prio = L;
p->next = L->next; // p->next = L
L->next = p;
L->prio = p;
}
else
{
p->prio = L;
p->next = L->next;
L->next->prio = p; // p->next->prio =p;
L->next = p;
}
L->len++;
printf("插入成功\n");
return 0;
}
// 尾插
int list_insert_tail(NodePtr L, datatype e)
{
// 判断逻辑
if (NULL == L)
{
printf("尾插插入失败\n");
return -1;
}
// 找到最后一个节点
NodePtr q = list_search_pos(L, L->len);
// 封装节点
NodePtr p = apply_node(e);
// 插入逻辑
p->next = q->next;
p->prio = q;
q->next = p;
L->len++;
printf("尾插插入成功\n");
return 0;
}
// 链表遍历
int list_show(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr q = L->next;
while (q != L)
{
printf("%c", q->data);
q = q->next;
}
putchar(10);
printf("遍历成功\n");
return 0;
}
// 头删
int list_delete_head(NodePtr L)
{
if (NULL == L || list_empty(L))
{
printf("头删失败\n");
return -1;
}
NodePtr p = L->next;
L->next = p->next;
p->next->prio = L;
free(p);
p = NULL;
L->len--;
printf("头删成功\n");
return 0;
}
// 链表删除
void list_destroy(NodePtr L)
{
if (NULL == L)
{
printf("删除失败\n");
return;
}
while (L->next == L)
{
list_delete_head(L);
}
free(L);
L = NULL;
printf("删除成功\n");
return;
}
// 任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
if (NULL == L || pos > L->len + 1 || pos < 1)
{
printf("删除失败\n");
return -1;
}
NodePtr q = list_search_pos(L, pos - 1);
NodePtr p = q->next;
q->next = p->next;
p->next->prio = q;
free(p);
p = NULL;
// NodePtr p = L->next;
// L->next = p->next;
// p->next->prio = L;
// free(p);
// p = NULL;
L->len--;
printf("按位置删除成功\n");
return 0;
}
//按位置修改
int list_change_pos(NodePtr L,int pos,datatype e)
{
if (NULL == L || pos > L->len + 1 || pos < 1)
{
printf("修改失败\n");
return -1;
}
NodePtr q = list_search_pos(L, pos);
q->data = e;
printf("按位置修改成功\n");
return 0;
}
#include "00.h"
int main(int argc, char const *argv[])
{
NodePtr L = list_create();
if (NULL == L )
{
return -1;
}
putchar(10);
list_insert_head(L,'H');
list_insert_head(L,'e');
list_insert_head(L,'l');
list_insert_head(L,'l');
list_insert_head(L,'o');
list_show(L);
putchar(10);
list_insert_tail(L,'Z');
list_show(L);
putchar(10);
list_delete_head(L);
list_show(L);
putchar(10);
list_delete_pos(L,3);
list_show(L);
putchar(10);
list_change_pos(L,4,'A');
list_show(L);
putchar(10);
list_destroy(L);
list_show(L);
putchar(10);
return 0;
}