作业:
1> 将双向链表和循环链表自己实现一遍,至少要实现创建、增、删、改、查、销毁工作
2> 使用循环链表完成约瑟夫环问题
work1.h
#ifndef WORK1_H
#define WORK1_H
#include <myhead.h>
typedef int datatype; //定义数据域的类型
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *prio;
struct Node *next;
}Node, *NodePtr;
NodePtr list_create();
//申请节点封装函数
NodePtr apply_node(datatype e);
int list_empty(NodePtr L);
//定义头插函数
int list_sert_head(NodePtr L,datatype e);
//定义展示函数
int list_show(NodePtr L);
//按位置查找返回节点
NodePtr list_search_pos(NodePtr L,int pos);
//链表任意位置删除
int list_delete_pos(NodePtr L,int pos);
//链表任意位置修改
int list_revise_pos(NodePtr L,int pos,datatype e);
//销毁工作
void list_destroy(NodePtr L);
#endif
work11.c
#include "work1.h"
//创建双向链表
NodePtr list_create()
{
//给头结点申请空间
NodePtr L = (NodePtr)malloc(sizeof(Node));
//判断逻辑
if(NULL == L)
{
printf("创建失败\n");
return NULL;
}
//初始化
L->len = 0;
L->prio = NULL;
L->next = NULL;
//创建成功
printf("创建成功\n");
return L;
}
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_empty(NodePtr L)
{
return L->next == NULL;
}
//定义头插函数
int list_sert_head(NodePtr L, datatype e)
{
//判断逻辑
if(NULL == L)
{
printf("插入失败\n");
return -1;
}
NodePtr p = apply_node(e);
if(NULL == p)
{
printf("头插失败\n");
return 0;
}
if(L->next == NULL)
{
L->next = p;
p->prio = L;
}else
{
p->prio = L;
p->next = L->next;
L->next->prio = p;
L->next = p;
}
printf("插入成功\n");
L->len++;
return 0;
}
int list_show(NodePtr L)
{
if(NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr p = L->next;
while(p)
{
printf("%d\t",p->data);
p=p->next;
}
printf("\n");
}
//按位置查找返回节点
NodePtr list_search_pos(NodePtr L,int pos)
{
if(NULL == L || list_empty(L)|| pos<0 ||pos>L->len)
{
printf("查找失败\n");
return NULL;
}
NodePtr p=L;
for(int i=0;i<pos;i++)
{
p=p->next;
}
return p;
}
//链表任意位置删除
int list_delete_pos(NodePtr L,int pos)
{
if(NULL == L || list_empty(L) || pos<1 ||pos>L->len)
{
printf("删除失败\n");
return -1;
}
NodePtr p = list_search_pos(L,pos);
if(p->next == NULL)
{
p->prio->next=NULL;
}else
{
p->prio->next=p->next;
p->next->prio=p->prio;
}
free(p);
p=NULL;
printf("删除成功\n");
}
//链表任意位置修改
int list_revise_pos(NodePtr L,int pos,datatype e)
{
if(NULL == L || list_empty(L)|| pos<1||pos>L->len)
{
printf("修改失败\n");
return -1;
}
NodePtr p = list_search_pos(L,pos);
p->data = e;
return 0;
}
//销毁工作
void list_destroy(NodePtr L)
{
//判断逻辑
if(NULL==L)
{
printf("删除失败\n");
return;
}
//删除所有节点
while(!list_empty(L))
{
list_delete_pos(L, 1);
}
//删除头结点
free(L);
L = NULL;
printf("链表释放成功\n");
}
work1.c
#include "work1.h"
int main(int argc, const char *argv[])
{
NodePtr L = list_create();
if(NULL == L)
{
return -1;
}
list_sert_head(L,5);
list_sert_head(L,2);
list_sert_head(L,0);
list_sert_head(L,0);
list_show(L);
list_delete_pos(L,1);
list_delete_pos(L,3);
list_show(L);
list_revise_pos(L,1,8);
list_show(L);
list_destroy(L);
list_show(L);
return 0;
}
work2.h
#ifndef WORK2_H
#define WORK2_H
#include <myhead.h>
typedef int datatype;
typedef struct Node
{
union
{
int len;
datatype data;
};
struct Node *next;
}Node,*NodePtr;
NodePtr list_create();
NodePtr apply_node(datatype e);
int list_empty(NodePtr L);
int list_sert_head(NodePtr L,datatype e);
int list_show(NodePtr L);
int list_delete_show(NodePtr L);
#endif
work22.c
#include "work2.h"
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;
}
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;
}
int list_empty(NodePtr L)
{
return L->next == L;
}
int list_sert_head(NodePtr L,datatype e)
{
if(NULL == L)
{
printf("插入失败\n");
return -1;
}
NodePtr p = apply_node(e);
p->next = L->next;
L->next = p;
L->len++;
return 0;
}
int list_show(NodePtr L)
{
if(NULL == L || list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr p =L->next;
while(p!=L)
{
printf("%d\t",p->data);
p=p->next;
}
printf("\n");
return 0;
}
int list_delete_show(NodePtr L)
{
if(NULL == L || list_empty(L))
{
printf("失败\n");
return -1;
}
NodePtr q = L;
NodePtr p = q->next;
for(int i=0;i<8;i++)
{
for(int j=0;j<3;j++)
{
if(q->next ==L)
{
q=L;
}
q=q->next;
}
p = q->next;
printf("第%d个出局的元素为%d\n",i+1,p->data);
q->next = p -> next;
free(p);
p=NULL;
L->len--;
}
}
work2.c
#include "work2.h"
int main(int argc, const char *argv[])
{
NodePtr L=list_create();
if(NULL == L)
{
return -1;
}
list_sert_head(L,2);
list_sert_head(L,9);
list_sert_head(L,7);
list_sert_head(L,5);
list_sert_head(L,6);
list_sert_head(L,8);
list_sert_head(L,1);
list_sert_head(L,3);
list_show(L);
list_delete_show(L);
return 0;
}
记得自己销毁一下(不销毁也没事)
三、双向链表
-
3.1 概念
-
1> 所谓双向链表,就是从任意一个节点既能存储其前驱节点信息也能存储后继节点信息 2> 节点结构体中增加一个指向前驱节点的指针 3> 头结点没有前驱,最后一个节点没有后继
-
-
3.2创建双向链表
-
1> 参数:不需要,只需要从堆区申请出一个头结点大小的空间,就创建了一个双向链表 2> 返回值:返回堆区空间中头结点的地址即可 3> 注意:需要将头结点数据域初始化为0,两个指针域分别初始化为NULL
-
-
3.3 判空
-
1> 跟单向链表的判空一致,只需要判断头结点的指针域是否为空即可
-
-
3.4 申请节点封装数据
-
3.5 头插
-
1> 参数:链表、要插入的元素 2> 返回值:int 3> 注意:对于空链表和非空链表的插入,有所不同,并且不能合并
-
-
3.6 链表遍历
-
1> 参数:链表 2> 返回值:int 3> 注意:需要使用一个遍历指针,从第一个节点出发,到最后一个节点
-
-
3.7 按位置查找节点
-
1> 参数:链表、要查找的位置 2> 返回值:成功返回找到的结点,失败返回NULL
-
-
3.8 任意位置删除
-
1> 参数:链表、要删除的位置 2> 返回值:int 3> 注意:对于双向链表的任意位置进行操作时(插入、删除),可以找到前驱结点处理也可以不用找到前驱结点
-
-
3.9 销毁链表
1> 参数:链表 2> 返回值:int 3> 注意:需要将所有的节点,全部删除后,然后删除头结点
所有代码
test1.h
#ifndef TEST1_H
#define TEST1_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);
//申请节点封装数据
NodePtr apply_node(datatype e);
//链表头插
int list_insert_head(NodePtr L,datatype e);
//遍历链表
int list_show(NodePtr L);
//按位置查找返回节点
NodePtr list_search_pos(NodePtr L,int pos);
//链表任意位置删除
int list_delete_pos(NodePtr L,int pos);
//链表删除
void list_destroy(NodePtr L);
test11.c
#include "test1.h"
//创建双向链表
NodePtr list_create()
{
//在堆区申请一个头节点
NodePtr L=(NodePtr) malloc (sizeof(Node));
if(NULL==L)
{
printf("创建失败\n");
return NULL;
}
//初始化
L->len = 0;
L->prio = NULL;
L->next = 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)
{
return -1;
}
if(list_empty(L))
{
p->prio = L;
L->next = p;
}else
{
p->prio = L;
p->next = L->next;
L->next ->prio = p;
L->next =p;
}
printf("插入成功\n");
L->len++;
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\t",q->data);
//遍历指针后移
q = q->next;
}
printf("\n");
}
//按位置查找返回节点
NodePtr list_search_pos(NodePtr L,int pos)
{
//判断逻辑
if(NULL == L || list_empty(L)|| pos<0 || pos>L->len)
{
printf("查找失败\n");
return NULL;
}
//查找逻辑
NodePtr q = L;
for(int i=0;i<pos;i++)
{
q = q->next;
}
//返回节点
return q;
}
//链表任意位置删除
int list_delete_pos(NodePtr L,int pos)
{
//判断逻辑
if(NULL == L || L->len<1 ||list_empty(L) || pos>L->len)
{
printf("删除失败\n");
return -1;
}
//找到要删除的节点
NodePtr q = list_search_pos(L,pos);
//删除逻辑
if(NULL == q->next)
{
q->prio->next = NULL;
free(q);
q = NULL;
}else
{
q->prio->next = q->next;
q->next->prio = q->prio;
free(q);
q=NULL;
}
printf("删除成功\n");
//表长变化
L->len--;
return 0;
}
//链表删除
void list_destroy(NodePtr L)
{
//判断逻辑
if(NULL ==L)
{
printf("删除失败\n");
return;
}
//删除所有节点
while(!list_empty(L))
{
list_delete_pos(L,1);
}
//删除头结点
free(L);
L = NULL;
printf("链表释放成功\n");
}
test1.c
#include "test1.h"
int main(int argc, const char *argv[])
{
//调用创建函数
NodePtr L=list_create();
if(NULL == L)
{
return -1;
}
list_insert_head(L,'Q');
list_insert_head(L,'W');
list_insert_head(L,'E');
list_insert_head(L,'R');
list_insert_head(L,'D');
list_insert_head(L,'F');
//遍历函数
list_show(L);
list_delete_pos(L,1);
list_delete_pos(L,3);
list_delete_pos(L,L->len);
list_show(L);
//释放链表
list_destroy(L);
L=NULL;
list_show(L);
return 0;
}
四、循环链表
-
4.1 概念
-
1> 循环链表,就是首尾相接的链表。 2> 单向循环链表:只需要将最后一个节点的指针域指向头结点即可 3> 双向循环链表:需要将最后一个阶段的指针域指向头结点,头结点的前驱指针指向最后一个阶段
-
-
4.2 单向链表操作
-
1> 节点结构体
-
2> 链表的创建 注意:创建头结点后,需要将头结点的指针域指向头结点自身
-
3> 链表判空
-
4> 申请节点封装数据
-
5> 按位置查找节点
-
6> 尾插
-
7> 链表遍历
-
8> 头删
-
9> 销毁链表
-
test2.h
#ifndef TEST2_H
#define TEST2_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,int pos);
//链表尾插
int list_insert_tail(NodePtr L,datatype e);
//链表遍历
int list_show(NodePtr L);
//链表头删
int list_delete_head(NodePtr L);
//链表销毁
void list_destroy(NodePtr L);
#endif
test22.c
#include "test2.h"
//创建循环列表
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,int pos)
{
if(NULL == L ||pos<0||pos>L->len)
{
printf("查找失败\n");
return NULL;
}
NodePtr q = L;
for(int i =0; i<pos; i++)
{
q = q->next;
}
return q;
}
//链表尾插
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);
if(NULL == p)
{
return -1;
}
//插入逻辑
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\t",q->data);
q = q->next;
}
printf("\n");
}
//链表头删
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(!list_empty(L))
{
list_delete_head(L);
}
free(L);
L = NULL;
printf("销毁成功\n");
}
test2.c
#include "test2.h"
int main(int argc, const char *argv[])
{
NodePtr L = list_create();
if(NULL == L)
{
return -1;
}
list_insert_tail(L,'Q');
list_insert_tail(L,'W');
list_insert_tail(L,'E');
list_insert_tail(L,'R');
list_insert_tail(L,'D');
list_insert_tail(L,'F');
list_show(L);
list_delete_head(L);
list_show(L);
list_destroy(L);
L = NULL;
return 0;
}