栈和队列的应用–求中算法
有三个容器对时间进行计量,第一个容器的球进行小时累计(最多11球),第二个容器的球进行5min累计(最多11球),第三个容器的球进行分钟累计(最多4球)。26个球表示11小时59分钟。27个球表示12小时。多长时间过后,依旧是1到27个顺序。
程序分析:需要3个栈和一个队列保存数据。
#include <stdio.h>
#include <stdlib.h>
#include "sqstack.h"
#include "queue.h"
#define NR_BALL 27
/**
* @brief 队列校验,判断队列是否按照顺序排列
* @param 队列的起始地址
* @retval 校验状态
*/
static int check(queue *qu)
{
int i = (qu->head+1)%MAXSIZE;
/*i不等于队尾*/
while (i!=qu->tail)
{
/*如果当前的数值比后面的数值大,不成立*/
if(qu->data[i]>qu->data[(i+1)%MAXSIZE])
return 0;
/*继续向后移动*/
i = (i+1)%MAXSIZE;
}
return 1;
}
求中算法主函数
int main()
{
queue *qu;
/*出来的球放在t,临时存放value*/
int t,time = 0,value;
sqstack *st_min,*st_fivemin,*st_hour;
/*创建*/
qu = qu_create();
if (qu == NULL)
exit(1);
st_min = st_create();
if (st_min == NULL)
exit(1);
st_fivemin = st_create();
if (st_fivemin == NULL)
exit(1);
st_hour = st_create();
if (st_hour == NULL)
exit(1);
/*创建球*/
for (int i = 1; i <= NR_BALL; i++)
/*入队27个*/
qu_enqueue(qu,&i);
/*遍历27个球*/
qu_travel(qu);
while (1)
{
/*出队*/
qu_dequeue(qu,&t);
/*出队之后时间增加*/
time++;
/*如果栈没有满,栈的最大为4*/
if (st_min->top != 3)
{
/*入栈操作*/
st_push(st_min,&t);
}
else
{
/*当栈非空*/
while (!st_isempty(st_min))
{
/*出栈,暂时存放在value中*/
st_pop(st_min,&value);
/*入队,入value*/
qu_enqueue(qu,&value);
}
/*5分钟的栈没满*/
if (st_fivemin->top != 10)
{
st_push(st_fivemin,&t);
}
/*5分钟的栈满*/
else
{
/*5分钟的栈非空*/
while (!st_isempty(st_fivemin))
{
/*出栈*/
st_pop(st_fivemin,&value);
/*入队*/
qu_enqueue(qu,&value);
}
/*10分钟的栈没满*/
if (st_hour->top!=10)
{
/*入栈*/
st_push(st_hour,&t);
}
/*10分钟的栈满了*/
else
{
/*10分钟的栈非空*/
while (!st_isempty(st_hour))
{
/*出栈*/
st_pop(st_hour,&value);
/*入队,最后一步*/
qu_enqueue(qu,&value);
}
/*入队*/
qu_enqueue(qu,&t);
/*检查qu的内容*/
if(check(qu))
break;
}
}
}
}
/*打印当前的时间*/
printf("time = %d \n",time);
/*遍历队列*/
qu_travel(qu);
qu_destory(qu);
/*销毁*/
st_destory(st_min);
st_destory(st_fivemin);
st_destory(st_hour);
exit(0);
}
树的存储
1、树的深度(层数)
2、度(子树的个数)
3、叶子、孩子、兄弟、堂兄弟(红黑树)
4、二叉树:满二叉树(2k次-1)、完全二叉树(只有倒数两层不满足两个孩子结点,完全二叉树的编号左孩子2n,右孩子2n+1)
5、存储:顺序、链式
6、树的遍历:按行、先序(根左右)、中序(左根右)、后序(左右根)
递归三要素:
1、找到出错的情况。
2、找到已知的已经满足的条件。
3、找到一层层递进或递出的情况。
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
#include "llist.h"
#define NAMESIZE 32
struct score_st
{
int id;
char name[NAMESIZE];
int math;
int chinese;
};
struct node_st
{
/*树的数据域*/
struct score_st data;
/*树的左子树和树的右子树*/
struct node_st *l,*r;
};
/*定义一个空树*/
static struct node_st *tree = NULL;
/*自定义打印函数*/
void print_s(struct score_st *d)
{
printf("%d %s %d %d \n",d->id,d->name,d->math,d->chinese);
}
/**
* @brief 树的插入
* @param 插入根的二级指针,插入的数据
* @retval 插入状态
*/
int insert(struct node_st **root,struct score_st *data)
{
struct node_st *node;
/*判断根是否为空*/
if (*root == NULL)
{
node = malloc(sizeof(*node));
if (node == NULL)
return -1;
/*数据域赋值,左右子树分别为空*/
node->data = *data;
node->l = NULL;
node->r = NULL;
/*根节点重新赋值*/
*root = node;
return 0;
}
/*插入数据的id小于等于根节点的数据id,*/
if (data->id <= (*root)->data.id)
/*递归调用左子树插入数据*/
return insert(&(*root)->l,data);
/*递归调用右子树插入数据*/
return insert(&(*root)->r,data);
}
/**
* @brief 树的查找
* @param 插入根的起始地址,查找数据的位置
* @retval 查找数据的起始地址
*/
struct score_st *find(struct node_st *root,int id)
{
/*错误判断*/
if (root == NULL)
return NULL;
/*找到数据位置*/
if (id == root->data.id)
/*返回结点的数据*/
return &root->data;
/*如果查找id小于根节点的id*/
if (id< root->data.id)
/*递归查找左子树*/
return find(root->l,id);
else
/*递归查找右子树*/
return find(root->r,id);
}
/**
* @brief 树的绘制的子函数
* @param 树的起始地址,绘制的层数
* @retval 查找数据的起始地址
*/
void draw_(struct node_st *root,int level)
{
if (root == NULL)
return;
/*递归调用绘制右子树*/
draw_(root->r,level+1);
/*打印level层空格*/
for (int i = 0; i < level; i++)
{
printf(" ");
}
/*绘制根节点*/
print_s(&root->data);
/*递归调用绘制左子树*/
draw_(root->l,level+1);
}
/**
* @brief 树的绘制
* @param 插入根的起始地址
* @retval None
*/
void draw(struct node_st *root)
{
draw_(root,0);
printf("\n\n");
//getchar();
}
平衡二叉树的实现
/**
* @brief 获取树的层数
* @param 树的起始地址
* @retval 树的层数
*/
static int get_num(struct node_st *root)
{
if (root == NULL)
return 0;
/*递归调用左右子树*/
return get_num(root->l)+1+get_num(root->r);
}
/**
* @brief 获取树的最小值
* @param 树的起始地址
* @retval 树的层数
*/
static struct node_st *find_min(struct node_st *root)
{
if (root->l == NULL)
return root;
/*顺着左子树一直找到左孩子为空的那个结点*/
return find_min(root->l);
}
/**
* @brief 树的左旋
* @param 树的一级指针
* @retval None
*/
static void turn_left(struct node_st **root)
{
/*保存当前root的根节点*/
struct node_st *cur = *root;
/*真的根就是旧的根的右孩子*/
*root = cur->r;
/*旧的根的右结点设为空*/
cur->r = NULL;
/*顺着当前左子树来找,找到最左边的结点*/
find_min(*root)->l = cur;
//draw(tree);
}
/**
* @brief 寻找树的最大值
* @param 树的一级指针
* @retval None
*/
static struct node_st * find_max(struct node_st *root)
{
if (root->r == NULL)
return root;
/*递归寻找右结点*/
return find_max(root->r);
}
/**
* @brief 树的右旋
* @param 树的一级指针
* @retval None
*/
static void turn_right(struct node_st **root)
{
struct node_st *cur = *root;
/*原来根的左孩子当做根节点*/
*root = cur->l;
/*原来根的左孩子根节点设为空*/
cur->l = NULL;
/*遍历寻找最大的数,挂上右结点*/
find_max(*root)->r = cur;
}
/**
* @brief 树的平衡
* @param 树的一级指针
* @retval None
* 左右子树的个数差值在1以内
*/
void balance(struct node_st **root)
{
/*接收左树和右树的差值*/
int sub;
if (*root == NULL)
return ;
/*循环计算差值并且判断*/
while(1)
{
/*左树和右树的差值*/
sub = get_num((*root)->l)-get_num((*root)->r);
/*树异常*/
if(sub >= -1 && sub <= 1)
break;
/*sub-1<-1左旋*/
if(sub < -1)
turn_left(root);
else
/*树右旋*/
turn_right(root);
}
/*递归调用*/
balance(&(*root)->l);
/*递归调用*/
balance(&(*root)->r);
}
/**
* @brief 树的删除
* @param 树的一级指针,删除的结点
* @retval None
*/
/*左边顶上来*/
void delete(struct node_st **root,int id)
{
struct node_st **node = root;
struct node_st *cur = NULL;
/*结点不为空,并且没有找到id*/
while (*node != NULL && (*node)->data.id != id)
{
/*如果id小于当前结点的id*/
if (id < (*node)->data.id)
/*向结点的左孩子移动*/
node = &(*node)->l;
else
/*向结点的右孩子移动*/
node = &(*node)->r;
}
if (*node == NULL)
return;
/*存放当前*node的位置*/
cur = *node;
/*如果左孩子为空,让右孩子顶上来*/
if (cur->l == NULL)
*node = cur->r;
else
{
/*顺着左孩子找,找到右结点,挂上来*/
*node = cur->l;
find_max(cur->l)->r = cur->r;
}
free(cur);
}
/**
* @brief 树的遍历
* @param 树的起始地址
* @retval None
*/
void travel(struct node_st *root)
{
/*退出条件,root为空*/
if (root == NULL)
return;
/*中序遍历*/
travel(root->l);
print_s(&root->data);
travel(root->r);
}
/**
* @brief 树的遍历(按层遍历)
* @param 树的起始地址
* @retval None
*/
void travel(struct node_st *root)
{
int ret;
QUEUE *qu;
/*存放出队的内容*/
struct node_st *cur;
/*队列的创建*/
qu = queue_create(sizeof(struct node_st*));
if (qu == NULL)
return;
queue_en(qu,&root);
while(1)
{
ret = queue_de(qu,&cur);
if (ret == -1)
break;
/*打印一下出队的数据*/
print_s(&cur->data);
/*如果左孩子不为空,那么当前的左孩子入队*/
if (cur->l != NULL)
queue_en(qu,&cur->l);
/*如果右孩子不为空,那么当前右孩子入队*/
if (cur->r != NULL)
queue_en(qu,&cur->r);
}
queue_destory(qu);
}
树的存储与平衡二叉树的实现主函数
int main()
{
/*给树规定范围,规定小数往左,大数往右*/
int arr [] = {1,2,3,7,6,5,9,8,4};
/*定义一级指针tree*/
struct node_st *tree = NULL;
struct score_st tmp,*datap;
for (int i = 0; i < sizeof(arr)/sizeof(*arr); i++)
{
tmp.id = arr[i];
snprintf(tmp.name,NAMESIZE,"stu%d",arr[i]);
tmp.math = rand()%100;
tmp.chinese = rand()%100;
/*树不带头结点,内容会发生变化,因此传递地址*/
insert(&tree,&tmp);
}
draw(tree);
balance(&tree);
draw(tree);
travel(tree);
/*树的删除测试*/
int tmpid = 5;
delete(&tree,tmpid);
draw(tree);
/*树的查找测试*/
int tmpid = 2;
datap = find(tree,tmpid);
if (datap == NULL)
printf("can't find the id %d",tmpid);
else
print_s(datap);
exit(0);
}
广义表的实现
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
#include <llist.h>
#define NAMESIZE 32
/*定义文件存放路径*/
#define FNAME "/tmp/out"
struct node_st
{
char data;
struct node_st *l,*r;
};
static struct node_st *tree = NULL;
/**
* @brief 树的插入
* @param 树的起始地址,插入数据
* @retval 插入状态
*/
int insert(struct node_st **root,int data)
{
struct node_st *node;
if (*root == NULL)
{
node = malloc(sizeof(*node));
if (node == NULL)
return -1;
node->data = data;
node->l = NULL;
node->r = NULL;
*root = node;
return 0;
}
if (data<= (*root)->data)
return insert(&(*root)->l,data);
return insert(&(*root)->r,data);
}
/**
* @brief 树的绘制的子函数
* @param 插入根的起始地址,绘制的层数
* @retval 查找数据的起始地址
*/
void draw_(struct node_st *root,int level)
{
if (root == NULL)
return;
draw_(root->r,level+1);
for (int i = 0; i < level; i++)
{
printf(" ");
}
/*打印结点的字符*/
printf("%c \n",root->data);
draw_(root->l,level+1);
}
/**
* @brief 树的绘制
* @param 插入根的起始地址
* @retval None
*/
void draw(struct node_st *root)
{
draw_(root,0);
printf("\n\n");
}
/**
* @brief 树的存放
* @param 插入根的起始地址,文件位置
* @retval 存放状态
*/
int save_(struct node_st *root,FILE *fp)
{
/*向文件中首先打印‘(’*/
fputc('(',fp);
/*如果为空,打印‘)’*/
if (root == NULL)
{
fputc(')',fp);
return 0;
}
/*向文件打印数据*/
fputc(root->data,fp);
/*递归打印数据*/
save_(root->l,fp);
/*递归打印数据*/
save_(root->r,fp);
/*打印右括号*/
fputc(')',fp);
return 0;
}
/**
* @brief 树的打印
* @param 插入根的起始地址,文件路径
* @retval 存放状态
*/
int save(struct node_st *root,const char *path)
{
FILE *fp;
/*文件为只写状态打开*/
fp = fopen(path,"w");
if (fp == NULL)
return -1;
/*不需要全部重复递归调用,因此再创建一个小函数*/
save_(tree,fp);
return 0;
}
广义表实现的主函数
int main()
{
char arr [] = "cefadjbh";
for (int i = 0; i < sizeof(arr)/sizeof(*arr)-1; i++)
{
insert(&tree,arr[i]);
}
draw(tree);
save(tree,FNAME);
exit(0);
}
广义表的反向实现
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
#include <llist.h>
#define NAMESIZE 32
#define FNAME "/tmp/1"
struct node_st
{
char data;
struct node_st *l,*r;
};
void draw_(struct node_st *root,int level)
{
if (root == NULL)
return;
draw_(root->r,level+1);
for (int i = 0; i < level; i++)
{
printf(" ");
}
printf("%c\n",root->data);
draw_(root->l,level+1);
}
void draw(struct node_st *root)
{
draw_(root,0);
printf("\n\n");
//getchar();
}
struct node_st * load_(FILE *fp)
{
int c;
struct node_st *root;
c = fgetc(fp);
/*从文件中获取字符*/
if (c != '(')
{
fprintf(stderr,"fgetc(): error.\n");
exit(1);
}
c = fgetc(fp);
if (c == ')')
return NULL;
/*分配内存空间*/
root = malloc(sizeof(*root));
if (root == NULL)
exit(1);
/*保存读取到的数据*/
root->data = c;
/*左孩子递归寻找*/
root->l = load_(fp);
/*右孩子递归寻找*/
root->r = load_(fp);
/*读取右括号*/
fgetc(fp);
return root;
}
struct node_st *load(const char *path)
{
FILE *fp;
struct node_st *root;
/*如果打开失败了*/
fp = fopen(path,"r");
if (fp == NULL)
return NULL;
/*递归调用root*/
root = load_(fp);
/*释放指针*/
fclose(fp);
/*返回打开成功的非空指针*/
return root;
}
广义表的反向实现
int main()
{
struct node_st *root;
/*接收load指针*/
root = load(FNAME);
/*绘制*/
draw(root);
exit(0);
}
搜索树的实现
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
#include <llist.h>
#include <string.h>
#define DESC_SIZE 256
#define FNAME "log"
#define KEY_SIZE 256
#define BUFSIZE 512
struct node_st
{
struct node_st *ch[26];
char desc[DESC_SIZE];
};
/**
* @brief 从文件中读取一行,把单词和文件拆分开
* @param 地址信息,关键字,描述信息
* @retval 存放状态
*/
int get_word(FILE *fp,char *key,char *desc)
{
int i,j;
char buf[BUFSIZE];
char *retp;
while (1)
{
/*读取文件当中的内容*/
retp = fgets(buf,BUFSIZE,fp);
if (retp == NULL)
return -1;
/*关键字赋值操作*/
for (i = 0; i < KEY_SIZE - 1 && buf[i]!= ':'; i++)
{
key[i] = buf[i];
}
/*最后一块空间补上尾0*/
key[i] = '\0';
i++;
/*描述细节赋值操作*/
for ( j = 0;j<DESC_SIZE -1&&buf[i]!= '\0';j++,i++)
{
desc[j] = buf[i];
}
desc[j] = '\0';
return 0;
}
}
/**
* @brief 申请内存空间,返回值交给别人指向
* @param None
* @retval 新结点的起始地址
*/
struct node_st * newnode(void)
{
struct node_st *node;
int i;
node = malloc(sizeof(*node));
if (node == NULL)
return NULL;
/*node的初始化*/
node->desc[0] = '\0';
for ( i = 0; i < 26; i++)
node->ch[i] = NULL;
return node;
}
/**
* @brief 树的插入
* @param 插入根的一级,待插入关键字,待插入描述信息
* @retval 存放状态
*/
int insert(struct node_st **root,char *key,char*desc)
{
if (*root == NULL)
{
*root = newnode();
if (*root == NULL)
return -1;
}
/**/
if (*key == '\0')
{
/*复制描述信息*/
strcpy((*root)->desc,desc);
return 0;
}
/*叶子结点递归调用*/
return insert((*root)->ch+*key-'a',key+1,desc);
}
/**
* @brief 树的查找
* @param 插入根的起始地址,文件路径
* @retval 存放状态
*/
char * find(struct node_st *root,char *key)
{
if (root == NULL)
return NULL;
if (*key == '\0')
return root->desc;
/*递归查找关键字*/
return find(root->ch[*key-'a'],key+1);
}
搜索树的实现的主函数
int main()
{
struct node_st *tree = NULL;
FILE *fp;
char *datap;
char desc[DESC_SIZE],key[KEY_SIZE];
int ret;
/*打开一个文件*/
fp = fopen(FNAME,"r");
if (fp == NULL)
{
fprintf(stderr,"fopen():error!\n");
exit(1);
}
while (1)
{
ret = get_word(fp,key,desc);
if (ret == -1 )
break;
insert(&tree,key,desc);
/*测试语句:输出key*/
puts(key);
/*测试语句:输出desc*/
puts(desc);
}
datap = find(tree,"donkey");
if (datap == NULL)
printf("can't not find");
else
puts(datap);
fclose(fp);
exit(0);
}