从零开始的嵌入式系统开发学习Day11(数据结构)

目录

一、队列

1.1 队列的概念

1.2 链式队列

1.2.1 定义结点结构体和队列结构体

1.2.2 创建一个空的队列

1.2.3 入队

1.2.4 出队

1.3 顺序队列(循环队列)

1.3.1 定义结点结构体

1.3.2 创建一个空的循环队列

1.3.3 判断队列是否为满

1.3.4 入队

1.3.5 判断队列是否为空

1.3.6 出队

1.3.7 遍历队列

二、树和二叉树

2.1 概念

2.2 二叉树

2.2.1 二叉树的性质

2.2.2 二叉树的存储

2.3 二叉树的存储方式

2.3.1 二叉树的顺序存储

 2.3.2 二叉树的链式存储

2.4 二叉树的操作

2.4.1 创建结点结构体

2.4.2 创建二叉树

2.4.3 遍历二叉树

2.5 二叉搜索树


一、队列

1.1 队列的概念

队列的性质:先进先出(FIFO)

队列的操作:

入队

出队

1.2 链式队列

        为了实现队列先进先出的原理,链式存储里可以采用头插法和尾删法或者尾插法和头删法实现功能,但是尾插和尾删需要将链表遍历一遍,效率太低

所以我们可以定义两个指针变量,一个front保存头结点的地址,一个rear保存最后一个结点的地址;入队操作时将新结点插入到rear对应的结点的后面,然后rear保存最后一个结点的地址,出队操作就是将头结点后面的结点删除。

1.2.1 定义结点结构体和队列结构体

#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#include <stdio.h>
#include <stdlib.h>


typedef int DataType;
//定义结点结构体
typedef struct node
{
    DataType data;
    struct node *next;
}node;
//定义队列结构体,便于操作链式操作队列的两个指针
typedef struct linkqueue
{
    node *front;    //保存头结点地址
    node *rear;     //保存最后一个的地址
}linkqueue;

#endif

1.2.2 创建一个空的队列

//创建一个空的队列
linkqueue *LinkeQueueCreate()
{
    //给linkqueue结构体的两个指针分配空间
    linkqueue *q = (linkqueue *)malloc(sizeof(linkqueue));
    //给node指针分配空间
    q->front = (node *)malloc(sizeof(node));
    q->rear = q->front;
    q->front->next = NULL;
    
    return q;
}

1.2.3 入队

//入队
void LinkQueueInput(linkqueue *q,DataType value)
{
    //申请一个新的结点并且赋值
    node *tmp = (node *)malloc(sizeof(node));
    tmp->data = value;
    tmp->next = NULL;


    //将新节点插入到对应的rear结点的后面
    q->rear->next = tmp;
    //将新节点的指针域保存NULL
    tmp->next = NULL;
    q->rear = tmp;    
}

1.2.4 出队

//出队
DataType LinkeQueueOutput(linkqueue *q)
{
    if(q->front->next == NULL)
    {
        printf("队列为空!\n");
        return (DataType)-1;
    }
    //头删法删除数据
    node *tmp = q->front->next;
    q->front->next = tmp->next;
    DataType value = tmp->data;
    free(tmp);
    tmp = NULL;
    //当队列为空时,将rear指针指向头结点
    if(q->front->next == NULL)
    {
        q->rear = q->front;
    }
    return value;
}

1.3 顺序队列(循环队列)

1.3.1 定义结点结构体

#ifndef _SEQUEUE_H_
#define _SEQUEUE_H_
#include <stdio.h>
#include <stdlib.h>


#define NUM 32
#define N (NUM + 1)


typedef int DataType;
typedef struct sequeue
{
    DataType data[N];
    int front;
    int rear;
}sequeue;

#endif

1.3.2 创建一个空的循环队列

//创建一个空的循环队列
sequeue *SequeueCreate()
{
    sequeue *q = (sequeue *)malloc(sizeof(sequeue));
    q->rear = q->front = 0;
    return q;
}

1.3.3 判断队列是否为满

//判断队列是否为满
int SequeueIsFull(sequeue *q)
{
    return (q->rear + 1) % N == q->front ? 1 : 0; 
}

1.3.4 入队

//入队
void SequeueInput(sequeue *q,DataType value)
{
    if(SequeueIsFull(q))
    {
        printf("队列为满,无法入队!\n");
        return;
    }
    else
    {
        q->data[q->rear] = value;
        if(q->rear == NUM)
        {
            q->rear = 0;
        }
        else
        {
            q->rear++;
        }
    }
}

1.3.5 判断队列是否为空

//判断队列是否为空
int SequeueIsEmpty(sequeue *q)
{
    return q->front == q->rear ? 1 : 0;
}

1.3.6 出队

//出队
DataType SequeueOutput(sequeue *q)
{
    if(SequeueIsEmpty(q))
    {
        return (DataType)-1;
    }
    else
    {
        DataType value = q->data[q->front];
        if(q->front == NUM)
        {
            q->front = 0;
        }
        else
        {
            q->front++;
        }
        //q->front = (q->front + 1) % N;
        return value;
    }
}

1.3.7 遍历队列

//遍历队列
void SequeuePrint(sequeue *q)
{
    if (SequeueIsEmpty(q))
    {
        printf("队列为空!\n");
    }
    else
    {
        while ( q->rear != q->front)
        {
            printf("%d ",q->data[q->front]);
            if (q->front == NUM)
            {
                q->front = 0;
            }
            else
            {
                q->front++;
            }
        }
        return;
    }
    
}

二、树和二叉树

2.1 概念

        如果数据和数据之间满足一对多的关系,将其逻辑结构称之为树

        最上层的第一个数据称之为根节点

        如果一个结点有直接后继,将这些后继称之为子节点或子树,这个结点称之为这些子节点的父节点

度数:

        一个结点的子树的个数称为该结点的度数

        一颗树的度数是指该树中结点最大度数

边数:

        一个结点系列,k1...ki 满足ki是ki+1的父节点,就称为一条从k1到ki的路径,路径的长度为i-1,即路径的边数

层数:

        结点的层数等于父节点的层数加一,根节点的层数为1,树种结点层数的最大值称为该树的高度或者深度。

终端节点(叶子结点):

        度数为零的节点称为树叶或终端节点,度数不为零的节点称为分支节 点,除根节点外的分支节点称为内部节点。

树的逻辑结构:

         树种任何结点都可以有多个或者0个直接后继结点(子节点)

        但是至多只能有一个直接前驱(父节点),根节点没有前驱结点

        叶子结点没有后继结点。

2.2 二叉树

        如果树种的每一个结点最多有两个,那么将这个树称为二叉树。

        二叉树与普通树不同,二叉树严格区分左孩子和右孩子,即使只有一个子节点也要区分左右

满二叉树 :深度为k(k≥1)时有2^k-1个节点的二叉树。

完全二叉树 :只有最下面两层有度数小于2的节点,且最下面一层的 叶节点集中在最左边的若干位置上。

2.2.1 二叉树的性质

性质1:在二叉树的第i层至多有2^(i -1)个结点。

性质2:深度为K的二叉树最多有2^k - 1个结点。

性质3:对任何一个二叉树,如果其终端结点数为n,度为2的结点数为m,则:n = m+1;

性质4:具有n个结点的完全二叉树,其深度为(log2n)+1或『log2(n+1)。

性质5:

如果对1棵有n个饥饿点的二叉树的饥饿点按层序编号,对任何一个结点i

(1)如果i= 1,则结点i是二叉树的根,无双亲,如果,如果i > 1,则其双亲结点为 i/2 。

(2)如果2i > n,则结点无左孩子,否则,其左孩子为2i。

(3)如果2i+ 1 > n,则结点无右孩子,否则,其右孩子为2i+1.

2.2.2 二叉树的存储

        完全二叉树的结点编号方法是从上到下,从左往右,根节点为1号结点

设完全二叉树的节点数为n,某结点编号为I

        2i <= n,有左孩子,其编号为2i,否则没有左孩子,本身是叶子结点

        2i+1 <= n,有右孩子,其编号为2i + 1,否则没有右孩子

2.3 二叉树的存储方式

2.3.1 二叉树的顺序存储

        因为无法保存当前二叉树是一个满二叉树或者完全二叉树,所以,顺序存储时,需要将不存在的结点预留位置,这样做就会浪费空间,所以一般不使用顺序存储

 2.3.2 二叉树的链式存储

        二叉树使用链式存储时,每一个结点需要定义一个结构体,里面至少有三个成员,分别是一个数据域和两个指针域组成,数据域保存数据,指针域分别保存左右子树的地址。

2.4 二叉树的操作

2.4.1 创建结点结构体

#ifndef _BINARYTREE_H_ 
#define _BINARYTREE_H_
#include <stdio.h>
#include <stdlib.h>


typedef int DataType;
typedef struct node
{
    DataType data;
    struct node *left;
    struct node *right;
}bitree_t;

#endif

2.4.2 创建二叉树

//创建二叉树
bitree_t *CreateTree(DataType *a,int length)
{
    bitree_t *array[11] = {0};
    int i;
    for(i = 0;i < length;i++ )
    {
        array[i] = (bitree_t *)malloc(sizeof(bitree_t));
        if(array[i] == NULL)
        {
            return NULL;
        }
        array[i]->data = a[i];
        array[i]->left = NULL;
        array[i]->right = NULL;
    }
    for(i = 0;i < length / 2;i++)
    {
        array[i]->left = array[2*i + 1];
        array[i]->right = array[2*i + 2];
    }
    return array[0];
}

2.4.3 遍历二叉树

        先序遍历:先访问树根,再访问左子树,最后访问右子树 (根左右)

        中序遍历:先访问左子树,再访问树根,最后访问右子树(左根右)

        后序遍历:先访问左子树,再访问右子树,最后访问树根(左右根)

 

先序遍历

//先序遍历
void PreOrder(bitree_t *root)
{
    if(root == NULL)
    {
        return;
    }
    else
    {
        printf("%d ",root->data);
        PreOrder(root->left);
        PreOrder(root->right);
    }
}

中序遍历

//中序遍历
void MidOrder(bitree_t *root)
{
    if(root == NULL)
    {
        return;
    }
    else
    {
        MidOrder(root->left);
        printf("%d ",root->data);
        MidOrder(root->right);
    }
}

后序遍历

//后序遍历
void PostOrder(bitree_t *root)
{
    if(root == NULL)
    {
        return;
    }
    else
    {
        PostOrder(root->left);
        PostOrder(root->right);
        printf("%d ",root->data);
    }
}

2.5 二叉搜索树

        定义:二叉搜索树,又被称为二叉查找树,其特点:左孩子比父节点小,右孩子比父节点大。

//创建二叉搜索树
bitree_t* CreateBSTree(bitree_t *root,DataType num)
{
    if (NULL == root)
    {
        root = (bitree_t *)malloc(sizeof(bitree_t) * 1);
        if(NULL == root)
        {
            return NULL;
        }
        root->data = num;
        root->left = NULL;
        root->right = NULL;
    }
    else
    {
        if(root->data > num)
        {
            root->left = CreateBSTree(root->left,num);
        }
        else
        {
            root->right = CreateBSTree(root->right,num);
        }
        return root;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值