一、思维导图
二、课后练习
1、使用循环链表完成约瑟夫环问题
//头文件
#ifndef JOSEPH_RING_H
#define JOSEPH_RING_H
#include <myhead.h>
typedef char datatype;
//定义单向循环链表结点
typedef struct Node
{
datatype data;
struct Node *next;
}Node,*NodePtr;
//创建单向循环链表
NodePtr list_create(datatype element);
//链表的判空
int list_empty(NodePtr H);
//链表结点的封装
NodePtr list_apply_node(datatype element);
//链表的尾插
int list_insert(NodePtr H,datatype element);
//链表的遍历
int list_show(NodePtr H);
//通过位置查找
NodePtr list_search_pos(NodePtr H,int pos);
//无头结点单向循环链表的头删
void deleteHead(NodePtr head);
//任意位置删除元素
int list_delete_pos(NodePtr H,int pos);
#endif
//功能函数
#include "Joseph_Ring.h"
//创建单向循环链表
NodePtr list_create(datatype element)
{
//在堆区申请头指针
NodePtr H = (NodePtr)malloc(sizeof(Node));
if(NULL == H)
{
printf("创建失败\n");
return NULL;
}
//初始化
H->next = H; //头结点指针域指向自己
H->data = element;
printf("创建成功\n");
return H;
}
//链表的判空
int list_empty(NodePtr H)
{
return H == NULL;
}
//链表结点的封装
NodePtr list_apply_node(datatype element)
{
//堆区申请结点
NodePtr p = (NodePtr)malloc(sizeof(Node));
if(NULL == p)
{
printf("申请失败\n");
return NULL;
}
//给结点赋值
p->data = element;
p->next = NULL;
return p;
}
//链表的尾插
int list_insert(NodePtr H,datatype element)
{
//判断逻辑
if(NULL == H)
{
printf("尾插失败\n");
return -1;
}
//申请结点
NodePtr p = list_apply_node(element);
if(NULL == p)
{
return -1;
}
//查找原链表尾结点
NodePtr q = H;
while(q->next != H)
{
q = q->next;
}
p->next = q->next;
q->next = p;
printf("插入成功\n");
return 0;
}
//链表的遍历
int list_show(NodePtr H)
{
//判断逻辑
if(NULL ==H)
{
printf("遍历失败\n");
return -1;
}
//遍历链表
NodePtr p = H; //定义遍历指针
do {
printf("%c\t",p->data);
p = p->next;
}
while(p!=H);
printf("\n");
return 0;
}
//链通过位置表查找
NodePtr list_search_pos(NodePtr H,int pos)
{
//判断逻辑
if(NULL == H)
{
printf("查找失败\n");
return NULL;
}
//查找逻辑
//遍历指针从头结点出发
NodePtr q = H;
for(int i =1;i<pos;i++)
{
q = q->next;
}
return q; //将找到的结点地址返回
}
//无头结点单向循环链表的头删
void deleteHead(NodePtr H)
{
//判断逻辑
if(NULL == H)
{
printf("头删错误\n");
return;
}
//定义指针遍历到结尾
NodePtr tail = H;
while(tail->next !=H)
{
tail = tail->next;
}
//删除头结点
NodePtr temp = H;
tail->next = H->next; //尾结点指向头结点的下一个结点
H = H->next; //头指针指向下一个结点
//释放原来的头结点
free(temp);
temp = NULL;
}
//单向链表任意位置删除
int list_delete_pos(NodePtr H,int pos)
{
//判断逻辑
if(NULL == H || pos<1)
{
printf("删除失败\n");
return -1;
}
//头结点删除
if(pos == 1)
{
deleteHead(H);
}
else
{
//找删除位置的前驱结点
NodePtr q = list_search_pos(H,pos-1);
//删除三部曲
NodePtr p = q->next; //标记
q->next = p->next; //断连
free(p); //释放
p = NULL;
printf("任意位置删除成功\n");
}
return 0;
}
//主函数
#include "Joseph_Ring.h"
int main(int argc, const char *argv[])
{
//设置
int num,mode,start;
printf("请输入总元素个数:");
scanf("%d",&num);
printf("请输入规则个数:");
scanf("%d",&mode);
printf("请输入开始位置:");
scanf("%d",&start);
getchar();
//输入第一个元素创建链表
datatype element;
printf("请输入首个元素:");
scanf("%c",&element);
getchar();
//创建头结点
NodePtr H = list_create(element);
//判断逻辑
if(NULL == H )
{
printf("error\n");
}
//循环插入元素
for(int i=0;i<num-1;i++)
{
datatype e;
printf("请输入元素:");
scanf("%c",&e);
getchar();
list_insert(H,e);
}
//展示原始顺序
list_show(H);
//按规则删除结点
//从start开始,每间隔mode个元素删除
//每轮删除将头结点指向下一轮的起始结点
//遍历到第start个结点s
NodePtr s = H;
for(int i=1;i<start;i++)
{
s = s->next;
}
printf("原始头结点:%c\n",H->data);
printf("规定起点:%c\n",s->data);
while(s->next != s)
{
//从第s个结点开始,遍历mode个结点,并删除第mode个结点
NodePtr m = s;
for(int i=1;i<mode;i++)
{
//记录m的
m = m->next;
}
//删除结点m
printf("删除:%c\n",m->data);
//将s指向m的下一个结点
//将m结点删除
NodePtr p = m->next;
//释放第m个
list_delete_pos(s,mode);
//s指向释放结点的下一个结点
s = p;
list_show(s);
}
return 0;
}
普通测试
头删测试
2、使用栈,完成进制转换(输入:一个整数,进制数,输出:该数的对应的进制数)
//头文件
#ifndef DEC_TO_BIN_H
#define DEC_TO_BIN_H
#include <myhead.h>
typedef int datatype;
#define MAX 100
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 element);
//出栈
void stack_pop(StackPtr S);
//遍历栈
void stack_show(StackPtr S);
//将整数转换成对应的进制数
void Dec_to_Bin(StackPtr S, int element,int num);
#endif
//功能函数
#include "Dec_to_Bin.h"
//创建栈
StackPtr stack_create()
{
//在堆区申请一个栈大小的空间
StackPtr S = (StackPtr)malloc(sizeof(Stack));
if(NULL == S)
{
printf("创建失败\n");
return NULL;
}
//栈申请成功,申请存储栈的空间
//申请MAX个datatype类型数据大小的空间
S->data = (datatype *)malloc(sizeof(datatype) * MAX);
if(NULL == S->data)
{
printf("申请栈存储空间失败\n");
return NULL;
}
//给空间内容初始化
memset(S->data,0,sizeof(datatype)*MAX);
//栈顶元素变量初始化
S->top = -1;
//返回栈地址
return S;
}
//判空
int stack_empty(StackPtr S)
{
return S->top == -1;
}
//判满
int stack_full(StackPtr S)
{
return S->top == MAX-1;
}
//入栈
void stack_push(StackPtr S,datatype element)
{
//判断逻辑
if(NULL == S || stack_full(S))
{
printf("入栈失败\n");
return;
}
//入栈
//先偏移栈顶位置
S->top++;
//再将数据压入栈中
S->data[S->top] = element;
}
//出栈
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>=0;i--)
{
printf("%d",S->data[i]);
}
printf("\n");
}
//将整数转换成对应的进制数
void Dec_to_Bin(StackPtr S, int element,int num)
{
//对element循环取余并压入栈中
while(element)
{
stack_push(S,element%num);
//将element除以num
element /= num;
}
}
//主函数
while(1)
{
//创建栈
StackPtr S = stack_create();
//提示输入
int element,num;
printf("请输入一个整数和你需要转换的进制数:");
scanf("%d%d",&element,&num);
//将整数转换成进制数存入栈中
Dec_to_Bin(S,element,num);
//循环出栈
printf("该整数的%d进制数为:",num);
while(S->top >0)
{
stack_pop(S);
}
printf("\n");
}
return 0;
}