双向链表
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 = LL->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;
}