LinuxC应用开发学习笔记(七)--数据结构

栈和队列的应用–求中算法

有三个容器对时间进行计量,第一个容器的球进行小时累计(最多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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值