链表、栈 Day19 20240723

一、链表与栈相关练习

1. 将双向链表和循环链表自己实现一遍,至少要实现创建、增、删、改、查、销毁工作

1.1双向链表

1.1.1 doublelinklist.h

#ifndef DOUBLELINKLIST_H
#define DOUBLELINKLIST_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_creatr();

//链表判空
int list_empty(NodePtr L);

//申请节点封装数据
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);

//链表任意位置修改
int list_update_pos(NodePtr L, int pos, datatype e);

//链表删除
void list_destroy(NodePtr L);

#endif

1.1.2 doublelinlist.c

#include "doublelinklist.h"

//创建双向链表
NodePtr list_creatr()
{
	//创建头结点
	NodePtr L = (NodePtr)malloc(sizeof(Node));
	
	//判断逻辑
	if(NULL == L)
	{
		printf("创建失败\n");
		return NULL;
	}

	//头结点初始化
	L->len = 0;			//链表初始长度为0
	L->prio = NULL;		//头结点无前驱节点,防止野指针
	L->next = NULL;		//防止野指针

	printf("创建成功\n");
	return L;
}

//链表判空
int list_empty(NodePtr L)
{	
	return NULL == L->next;
}

//申请节点封装数据
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;
	}

	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");
	return 0;
}

//按位置查找返回节点
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->next;
	for(int i=1; i<pos; i++)		//遍历到pos所在位置
	{
		P = P->next;	
	}

	return P;
}

//链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
	//判读逻辑
	if(NULL==L || list_empty(L) || pos<0 || pos>L->len)
	{
		printf("删除失败\n");
		return -1;
	}

	//删除逻辑
	NodePtr Q = list_search_pos(L, pos);
	if(pos < L->len)
	{
		Q->prio->next = Q->next;
		Q->next->prio = Q->prio;
	}
	else
	{
		Q->prio->next = NULL;
	}
	free(Q);
	Q = NULL;		//防止野指针

	L->len--;		//表长变化
	return 0;
}

//链表任意位置修改
int list_update_pos(NodePtr L, int pos, datatype e)
{
	//判读逻辑
	if(NULL==L || list_empty(L) || pos<0 || pos>L->len)
	{
		printf("修改失败\n");
		return -1;
	}

	//修改逻辑
	NodePtr Q = list_search_pos(L, pos);
	Q->data = e;
	return 0;
}

//链表删除
void list_destroy(NodePtr L)
{
	//判断逻辑
	if(NULL==L)
	{
		printf("删除失败\n");
		return ;
	}
	
	//删除逻辑
	while(L->next)
	{
		list_delete_pos(L, 1);
	}
	free(L);
	L = NULL;		//防止野指针

	printf("删除成功\n");
	return ;
}

1.1.3 main.c

#include "doublelinklist.h"

int main(int argc, const char *argv[])
{
	//调用函数创建链表
	NodePtr L = list_creatr();
	//判断逻辑
	if(L == NULL)
	{
		return -1;
	}

	//调用函数头插链表
	list_insert_head(L, 'a');
	list_insert_head(L, 'b');
	list_insert_head(L, 'c');
	list_insert_head(L, 'd');
	list_insert_head(L, 'e');
	
	//调用函数遍历链表
	list_show(L);
	
	//调用函数查找节点
	NodePtr P = list_search_pos(L, 3);
	printf("%c\n", P->data);

	//调用函数任意位置删除
	list_delete_pos(L, 1);
	list_delete_pos(L, 3);
	list_delete_pos(L, L->len);
	list_show(L);
	
	//调用函数任意位置修改
	list_update_pos(L, 1, 'A');
	list_update_pos(L, L->len, 'B');
	list_show(L);

	//调用函数删除链表
	list_destroy(L);
	L = NULL;		//防止野指针
	list_show(L);

	return 0;
}

1.1.4 程序运行截图

1.2循环链表

1.2.1 looplinklist.h

#ifndef LOOPLINKLIST_H
#define LOOPLINKLIST_H
#include <myhead.h>

//定义数据类型
typedef char datatype;

//定义节点类型
typedef struct Node
{
	union
	{
		int len;
		datatype data;
	};
	struct Node *next;
}Node, *NodePtr;

//创建循环链表
NodePtr list_creat();

//链表判空
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_update_pos(NodePtr L, int pos, datatype e);

//链表遍历
int list_show(NodePtr L);

//链表头删
int list_delete_head(NodePtr L);

//链表释放
void list_destroy(NodePtr L);


#endif

1.2.2 looplinklist.c

#include "looplinklist.h"

//创建循环链表
NodePtr list_creat()
{
	//创建头结点,并在堆区申请空间
	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 == L->next;
}

//链表申请空间封装节点
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 P = L->next;
	for(int i=1; i<pos; i++)
	{
		P = P->next;
	}

	return P;
}

//链表尾插
int list_insert_tail(NodePtr L, datatype e)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("尾插失败\n");
		return -1;
	}

	//尾插逻辑
	NodePtr P = apply_node(e);
	if(NULL == P)
	{
		return -1;
	}
	NodePtr Q = list_search_pos(L, L->len);
	P->next = L;
	Q->next = P;
	L->len++;

	return 0;
}

//链表按位置修改
int list_update_pos(NodePtr L, int pos, datatype e)
{
	//判断逻辑
	if(NULL == L || list_empty(L) || pos<0 || pos>L->len)
	{
		printf("修改失败\n");
		return -1;
	}

	//修改逻辑
	NodePtr P = list_search_pos(L, pos);
	if(NULL == P)
	{
		printf("修改失败\n");
		return -1;
	}
	P->data = e;

	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("%c\t", P->data);
		P = P->next;
	}

	printf("\n");
	return 0;
}

//链表头删
int list_delete_head(NodePtr L)
{
	//判断逻辑
	if(NULL==L || list_empty(L))
	{
		printf("头删失败\n");
		return -1;
	}

	//头删逻辑
	NodePtr Q = L->next;	//标记第一个节点
	L->next = L->next->next;
	free(Q);
	Q = NULL;				//防止野指针
	L->len--;				//表长变化

	return 0;
}

//链表释放
void list_destroy(NodePtr L)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("释放失败\n");
		return ;
	}
	
	//释放逻辑
	while(L != L->next)
	{
		list_delete_head(L);
	}
	free(L);
	L = NULL;		//防止野指针

	printf("释放成功\n");
}

1.2.3 main.c

#include "looplinklist.h"

int main(int argc, const char *argv[])
{
	//调用函数创建链表
	NodePtr L = list_creat();

	//调用函数尾插链表
	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_delete_head(L);
	list_show(L);
	list_delete_head(L);
	list_show(L);
	list_delete_head(L);
	list_show(L);
	list_delete_head(L);
	list_show(L);
	
	//调用函数尾插链表
	list_insert_tail(L, 'D');
	list_insert_tail(L, 'R');
	list_insert_tail(L, 'E');
	list_insert_tail(L, 'W');
	list_insert_tail(L, 'Q');
	list_show(L);

	//调用函数任意位置修改
	list_update_pos(L, 1, 'A');
	list_update_pos(L, 2, 'B');
	list_update_pos(L, L->len, 'C');
	list_show(L);


	//调用函数释放链表
	list_destroy(L);
	L = NULL;	//防止野指针
	list_show(L);

	return 0;
}

1.2.4 程序运行截图

2.使用循环链表完成约瑟夫环问题

2.1 looplinklist.h

#ifndef LOOPLINKLIST_H
#define LOOPLINKLIST_H
#include <myhead.h>

//定义数据类型
typedef int datatype;

//定义节点类型
typedef struct Node
{
	union
	{
		int len;
		datatype data;
	};
	struct Node *next;
}Node, *NodePtr;

//创建循环链表
NodePtr list_creat();

//链表判空
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_update_pos(NodePtr L, int pos, datatype e);

//链表遍历
int list_show(NodePtr L);

//链表头删
int list_delete_head(NodePtr L);

//链表释放
void list_destroy(NodePtr L);

//约瑟夫环问题
void josephus();


#endif

2.2 looplinklist.c

#include "looplinklist.h"

//创建循环链表
NodePtr list_creat()
{
	//创建头结点,并在堆区申请空间
	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 == L->next;
}

//链表申请空间封装节点
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 P = L->next;
	for(int i=1; i<pos; i++)
	{
		P = P->next;
	}

	return P;
}

//链表尾插
int list_insert_tail(NodePtr L, datatype e)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("尾插失败\n");
		return -1;
	}

	//尾插逻辑
	NodePtr P = apply_node(e);
	if(NULL == P)
	{
		return -1;
	}
	NodePtr Q = list_search_pos(L, L->len);
	P->next = L;
	Q->next = P;
	L->len++;

	return 0;
}

//链表按位置修改
int list_update_pos(NodePtr L, int pos, datatype e)
{
	//判断逻辑
	if(NULL == L || list_empty(L) || pos<0 || pos>L->len)
	{
		printf("修改失败\n");
		return -1;
	}

	//修改逻辑
	NodePtr P = list_search_pos(L, pos);
	if(NULL == P)
	{
		printf("修改失败\n");
		return -1;
	}
	P->data = e;

	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_head(NodePtr L)
{
	//判断逻辑
	if(NULL==L || list_empty(L))
	{
		printf("头删失败\n");
		return -1;
	}

	//头删逻辑
	NodePtr Q = L->next;	//标记第一个节点
	L->next = L->next->next;
	free(Q);
	Q = NULL;				//防止野指针
	L->len--;				//表长变化

	return 0;
}

//链表释放
void list_destroy(NodePtr L)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("释放失败\n");
		return ;
	}
	
	//释放逻辑
	while(L != L->next)
	{
		list_delete_head(L);
	}
	free(L);
	L = NULL;		//防止野指针

	printf("释放成功\n");
}

//约瑟夫环问题
void josephus()
{
	//创建2个循环链表
	NodePtr L = list_creat();		//存储问题
	int sum = 0,		//约瑟夫环总长度
		size = 0;		//间隔
	printf("请输入约瑟夫环的长度:");
	scanf("%d", &sum);
	printf("请输入约瑟夫环的间隔:");
	scanf("%d", &size);
	for(int i=1; i<=sum; i++)
	{
		//将约瑟夫环的数据插入链表
		list_insert_tail(L, i);
	}
	
	//遍历当前约瑟夫环
	list_show(L);

	//问题解决逻辑
	NodePtr Q = L;
	printf("约瑟夫环求解后的顺序为:\n");
	while(!list_empty(L))
	{
		for(int i=1; i<size; i++)
		{	
			if(Q->next == L)
			{
				Q = L->next;
			}
			else
			{
				Q = Q->next;	
			}
		}
		if(1 == L->len)
		{
			printf("%d\n", L->next->data);
			list_destroy(L);
			L = NULL;
			break;
		}
		else if(Q->next == L)
		{
			Q = L->next;
			NodePtr H = Q->next;
			printf("%d\t", H->data);
			Q->next = H->next;
			free(H);
			H = NULL;
			L->len--;
		}
		else
		{
			NodePtr H = Q->next;
			printf("%d\t", H->data);
			Q->next = H->next;
			free(H);
			H = NULL;
			L->len--;
		}
	}
	printf("\n");
}

2.3 main.c

#include "looplinklist.h"

int main(int argc, const char *argv[])
{
	//调用约瑟夫环求解函数
	josephus();

	return 0;
}

2.4 程序运行截图

3.使用栈,完成进制转换,输入:一个整数;进制数,输出:该数的对应的进制数

3.1 seqstack.h

#ifndef SEQSTACK_H
#define SEQSTACK_H
#include <myhead.h>

typedef char datatype;	//数据类型
#define MAX 31			//顺序栈的最大容量
//定义顺序栈的类型
typedef struct 
{
	datatype *data;
	int top;
}Stack, *StackPtr;

//创建栈
StackPtr stack_create();

//判空
int stack_empty(StackPtr S);

//判满
int stack_full(StackPtr S);

//入栈
void stack_push(StackPtr S, datatype e);

//出栈
void stack_pop(StackPtr S);

//遍历栈
void stack_show(StackPtr S);

//获取栈顶元素地址
datatype* stack_get_top(StackPtr S);

//求栈的大小
int stack_size(StackPtr S);

//释放栈
void stack_destroy(StackPtr S);

//进制转换函数
void decimal_conversion_stack();



#endif

3.2 seqstack.c


#include "seqstack.h"

//创建栈
StackPtr stack_create()
{
	//在堆区为栈申请空间
	StackPtr S = (StackPtr)malloc(sizeof(Stack));
	if(NULL == S)
	{
		printf("创建失败\n");
		return NULL;
	}

	//程序执行至此,表示栈申请出来了,但存储栈的空间还没有申请
	S->data = (datatype *)malloc(sizeof(datatype) * MAX);
	if(NULL == S)
	{
		printf("创建失败\n");
		return NULL;
	}
	//memset(S->data, 0, sizeof(datatype)*MAX);
	bzero(S->data, sizeof(datatype)*MAX);	
	S->top = -1;

	printf("创建成功\n");
	return S;
}

//判空
int stack_empty(StackPtr S)
{
	return -1 == S->top;
}

//判满
int stack_full(StackPtr S)
{
	return MAX-1 == S->top;
}

//入栈
void stack_push(StackPtr S, datatype e)
{
	//判断逻辑
	if(NULL==S || stack_full(S))
	{
		printf("入栈失败\n");
		return ;
	}

	//入栈逻辑
	S->top++;
	S->data[S->top] = e;
}

//出栈
void stack_pop(StackPtr S)
{
	//判断逻辑
	if(NULL==S || stack_empty(S))
	{
		printf("出栈失败\n");
		return ;
	}

	//出栈逻辑
	printf("%d出栈成功\n", S->data[S->top]);
	S->top--;
}

//遍历栈
void stack_show(StackPtr S)
{
	//判断逻辑
	if(NULL==S || stack_empty(S))
	{
		printf("遍历失败\n");
		return ;
	}

	//遍历逻辑
	for(int i=S->top; i>-1; i--)
	{
		printf("%c\t", S->data[i]);
	}

	printf("\n");
}

//获取栈顶元素地址
datatype* stack_get_top(StackPtr S)
{
	//判断逻辑
	if(NULL==S || stack_empty(S))
	{
		printf("获取失败\n");
		return NULL;
	}

	return &S->data[S->top];
}

//求栈的大小
int stack_size(StackPtr S)
{
	//判断逻辑
	if(NULL==S)
	{
		printf("求大小失败\n");
		return -1;
	}

	return S->top+1;
}

//释放栈
void stack_destroy(StackPtr S)
{
	//判断逻辑
	if(NULL==S)
	{
		printf("释放失败\n");
		return ;
	}

	//释放逻辑
	free(S->data);
	free(S);
	S = NULL;
}


//进制转换函数
void decimal_conversion_stack()
{
	int num = 0, 			//定义一个十进制整数
	 	decimal = 0;		//定义一个进制数
	char remainder = '0';		//定义一个余数
	
	//创建栈用于储存转换后的进制数
	StackPtr S = stack_create();
	
	//输入数据
	while(num<0 || decimal<2)
	{
		printf("请输入一个正整数:");
		scanf("%d", &num);
		printf("请输入您需要转换的进制数:");
		scanf("%d", &decimal);
		if(num<0 || decimal<2)
		{
			printf("输入错误,请重新输入\n");
		}
	}
	
	//转换逻辑
	while(num)
	{
		remainder = (num % decimal);	//求余数
		num /= decimal;				//求商
		//当大于十进制时
		if(remainder > 9)
		{
			remainder += 55;
		}
		else
		{
			remainder += 48;
		}	
		//余数入栈
		stack_push(S, remainder);	
	}

	printf("%d的%d进制数为:\n", num, decimal);
	//遍历栈
	stack_show(S);

	//销毁栈
	stack_destroy(S);
	S = NULL;		//防止野指针
}

3.3 main.c

#include "seqstack.h"

int main(int argc, const char *argv[])
{
	//调用函数创建栈
	StackPtr S = stack_create();
	if(NULL == S)
	{
		return -1;
	}

	//调用函数入栈
	stack_push(S, 5+48);
	stack_push(S, 2+48);
	stack_push(S, 0+48);
	stack_push(S, 1+48);
	stack_push(S, 3+48);
	stack_push(S, 1+48);
	stack_push(S, 4+48);

	//调用函数遍历栈
	stack_show(S);

	//调用函数出栈
	stack_pop(S);
	stack_pop(S);
	stack_pop(S);
	stack_pop(S);
	stack_show(S);
	
	//调用函数求栈的大小
	int size = stack_size(S);
	printf("栈的大小为:%d\n", size);
	
	//调用函数释放栈
	stack_destroy(S);
	S = NULL;
	stack_show(S);
	
	//进制转换函数
	int mune = 1;
	while(mune)
	{
		decimal_conversion_stack();	
		printf("0退出,1继续:");
		scanf("%d", &mune);
		printf("\n");
	}

	
	return 0;
}

2.4 程序运行截图

二、链表、栈相关知识思维导图

1.双向链表

2.循环链表

3.顺序栈

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值