数据结构——树

分层次组织在管理上具有更高的效率

查找:根据某个给定关键字K,从集合R中找出关键字与K相同的记录

静态查找:集合中记录是固定的,没有插入和删除操作,只有查找

动态查找:集合中记录时动态变化的,除查找,还可以发生插入和删除

1、结构体定义

typedef struct LNode *List;
struct LNode{
    ElementType Element[MAXSIZE];
    int Length;
};

2、顺序查找(带哨兵)

int SequentialSearch(List Tbl,ElementType k)
{//在Element[1]~Element[n]中查找关键字为K的数据元素
    int i;
    Tbl->Element[0]=K;    //建立哨兵
    for(i=Tbl->Length;Tble->Element[i]!=K;i--);
    return i;    //查找成功返回所在单元下标;不成功返回0
}

无哨兵的查找

int SequentialSearch(List Tbl,ElementType K)
{//在ElementType[1]~ElementType[n]中查找关键字K的数据元素
    int i;
    
    for(i=Tbl->Length;i>0&&Tbl->Element[i]!=K;i--);
    return i;
}

2、方法二:二分查找(Binary Search)

假设n个数组元素的关键字满足有序(比如说小到大)k1<k2<.....kn,并且时连续存放(数组),那么就可以进行二分查找。

缺少代码

3、树的定义

树(Tree):n(>=0)个节点构成的有限集合,当n=0,称为空树,对于任一课非空树(n>0),它具备以下性质:

树中有一个称为“根(Root)”的特殊节点,用r表示;其余结点可分为m(m>0)个互不相交的有限集T1,T2....TN,其中每个集合本身又是一棵树,称原来树的“子树(subTree)”

树的一些基本术语

1、结点的度(Degree):结点的子树个数

2、树的度:树所有结点中最大的度数

3、叶结点:度为0的结点

4、父节点:有子树的结点是其子树的根结点的父节点

5、子节点:若A结点时B结点的父节点,则称B结点时A结点的子节点;子结点也称孩子结点

6、兄弟结点:具有同一父结点的个节点彼此时兄弟结点。

7、路径和路径长度:从结点n1到nk的路径为一个结点序列n1,n2......nk,ni是ni+1的父节点。路径包含边的个数为路径的长度。

9、祖先结点:沿树根到某一结点路径上的所有结点都是这个结点的祖先结点。

10、子孙结点:某一结点的字数中所有结点时这个结点的子孙。

11、结点的层次:规定根结点在1层,其他任一结点的层数时其父节点的层数加1.

12、树的深度:树中所有结点中的最大层次时这棵树的深度。

2、二叉树的定义

二叉树T:一个有穷的结点集合,这个集合可以为空,若部位空,则他是由分界点和称为其左子树TL和右子树TR的两个不相交的二叉树组成。二叉树的子树有左右顺序之分。

特殊二叉树:斜二叉树、完美二叉树、完全二叉树、完全二叉树

2.1、二叉树几个重要性质

数据对象集:一个有穷的结点集合。若不为空,则由根节点和其左、右二叉子树组成。

操作树:BT∈BinTree,item∈ElementType,重要操作有:

1、Boolean IsEmpty(BinTree BT):判别BT是否为空;

2、void Traversal(BinTree BT):遍历,按某顺序访问每个结点

3、BinTree CreatBinTree():创建一个二叉树 。

常用的遍历方法有:

void PreOrderTraversal(BinTree BT):先序——根,左子树,右子树;

void InOrderTraversal(BinTree BT):中序——左子树,根,右子树;

void PostOrderTraversal(BinTree BT):后续——左子树,右子树,根

void LevelOrderTraversal(BinTree BT):层次遍历,从上到下,从左到右

 2.2、二叉树的存储结构

2.2.1、顺序存储结构

完全二叉树:按从上到下,从左到右顺序存储n个结点的完全二叉树的结点父子关系:  

非根结点(序号i>1)的父节点的序号事|i/2|;

结点(序号为i)的左孩子的序号事2i,(若2i<=n,则没有左孩子)

结点(序号为i)的右孩子结点的序号是2i+1,(若2i+1<=n,则没有由孩子);

2.2.2、链表存储

typedef strcut TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode
{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

2.3、二叉树的遍历

(1)先序遍历,访问根节点、然后遍历其左子树、再遍历其右子树

void PreOrderTraversal(BinTree BT)
{
    if(BT){
        printf(%d,BT->Data);
        PreOrderTraversal(Bt->Left);
        PreOrderTraversal(BT->Ritht);
    
    }
}

(2)中序遍历,先遍历左子树,访问根节点,遍历其右结点。

void InOrderTraversal(BinTree BT)
{
    if(BT)
    {
        InOrderTraversal(BT->Left);
        printf("%d",BT->Data);
        InorderTraversal(BT->Right)
    }
}

(3)后续遍历

后续遍历其左子树,后续右子树,最后是根结点

void PostOrderTraversal(BinTree BT)
{
    if(BT)
    {
        PostOrderTraversal(BT->Left);
        PostOrderTraversal(BT->Right);
        Printf("%d",BT->Data);
    }
}

先序、中序、后序遍历过程:遍历过程中经过结点的路线一样,只是访问个节点的时机不同。

2.3 二叉树的非递归遍历

中序遍历非递归遍历算法,算法实现的基本思路:使用堆栈

遇到一个结点,就把他压栈,并去遍历她的子树;当左子树遍历结束后,从栈顶弹出这个结点并访问它;然后按其右指针再去中序遍历该结点的右子树

void InOrderTraversal(BinTree BT)
{
    BinTree T=BT;
    Stack S = CreatStack(MaxSize);//创建并初始化堆栈
    while(T||!IsEmpty(s){
        while(T){    //一直向左并将沿途结点压入堆栈
            Push(S,T);
            T=T->Left;
        }
        if(!IsEmpty(s)){
            T=pop(S);    //结点弹出堆栈
            printf("%d",T->Data);    //访问打印结点
            T=T->Right;    //转向右子树
        }
    }
}

4、层序遍历

 队列实现:遍历从根节点开始,首先将根结点入队,然后开始执行:结点出队、访问该结点、其左右儿子入队

层序基本过程:先根节点入队,然后:

从队列中取出一个元素,访问该元素所指结点,若该元素所指结点的左、右孩子结点非空则将其左、右孩子的指针顺序入队。

void LevelOrderTraverl (BinTree BT)
{
    Queue Q;    BinTree T;
    if(!BT) return;    //若是空树则直接返回
    Q = CreatQueue(MaxSize);  //创建并初始化队列Q
    AddQ(Q,BT);
    while(!IsEmptyQ(Q))
    {
        T=DeleteQ(Q);
        printf("%d\n",T->Data);    //访问去除队列的结点
        if (T->Left)    AddQ(Q ,T->Left);
        if(T->Right)    AddQ(Q ,T->Right);
    }
}

5、程序框架搭建

int main()    
{
    Tree R1,R2;
    
    R1=BuildTree(T1);    //建二叉树1
    R2=BuildTree(T2);    //剪二叉树2

    if(lsomorphic(R1,R2)) printf("yes\n");    //判断是否同构并输出
    else printf("No\n");
    return 0;
}

如何建立二叉树

Tree BuildTree(struct TreeNode t[])
{
    scanf("%d\n",&N)
    if(N)
    {
        for(i=0;i<N;i++)check[i]=0;
        for(i=0;i<N;i++)
        {
            scanf("%c%c%c\n",&T[i].Element,&cl,&cr);
            if(cl!='-')
            {
                T[i].Left=cl-'0';
                check[T[i].Left]=1;
            }
            else 
                T[i].Left=Null;
        }
        for(i=0;i<N;i++)
            if(!check[i]) break;
            Root=i;
    }
    return Root;
}

判断两个二叉树同构

int Isomorphic(Tree R1,Tree R2)
{
    if((R1==Null)&&(R2==Null))
        return 0;
    if((R1==Null)&&(R2==Null))||((R1!=Null)&&(R2==Null))
        return 0;
    if(T1[R1].Element!=T2[R2].Element)
        return 0;
    if((T1[R1].Left==Null)&&(T2[R2].Left==Null))
        return Isomorphic(T1[R1].Right,T2[R2].Right);
}

int Isomorphic(Tree R1,Tree R2)
{
    if(((T1[R1].Left!=Null)&&(T2[R2].Left!=Null))&&
       ((T1[T1[R1].Left].Element)==T2[T2[R2].Left].Element) )
        return (Isomorphic(T1[R1].Left,T2[R2].Left)&&
                Isomorphic(T1[R1].Right,T2[R2].Right))
     else
        return (Isomorphic(T1[R1].Left,T2[R2].Right)&&
                Isomorphic(T1[R1].Right,T2[R2].Left))        
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Keil MDK中使用可以通过定义节点结构体和使用指针来实现。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义节点结构体 typedef struct node { int data; struct node *left; struct node *right; } TreeNode; // 创建节点 TreeNode* create_node(int data) { TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); node->data = data; node->left = NULL; node->right = NULL; return node; } // 插入节点 TreeNode* insert_node(TreeNode* root, int data) { if (root == NULL) { return create_node(data); } if (data < root->data) { root->left = insert_node(root->left, data); } else { root->right = insert_node(root->right, data); } return root; } // 计算的深度 int tree_depth(TreeNode* root) { if (root == NULL) { return 0; } int left_depth = tree_depth(root->left); int right_depth = tree_depth(root->right); return (left_depth > right_depth ? left_depth : right_depth) + 1; } int main() { // 创建根节点 TreeNode* root = create_node(5); // 插入节点 root = insert_node(root, 3); root = insert_node(root, 7); root = insert_node(root, 1); root = insert_node(root, 4); root = insert_node(root, 6); root = insert_node(root, 8); // 计算的深度并输出 int depth = tree_depth(root); printf("Tree Depth: %d\n", depth); return 0; } ``` 在这个示例代码中,我们首先定义了一个节点结构体,包含了节点数据和左右子节点指针。然后我们定义了创建节点和插入节点的函数,使用递归的方式实现。最后我们定义了计算深度的函数,并在main函数中使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值