数据结构学习笔记--树的学习上

学习目标:

数据结构学习笔记
树(上)


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


、、

树(上)

1.树与树的表示

什么是树

树(Tree)是n(n≥0)个结点的有限集T,并且当n>0时满足下列条件:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可以划分为m(m>0)个互不相交的有限集T1、T2 、…、Tm,每个集Ti(1≤i≤m)均为树,且称为树T的子树(SubTree)。
特别地,不含任何结点(即n=0)的树,称为空树。
如下是一颗树:
在这里插入图片描述

树使得分层次在管理上具有更高的效率

数据管理的基本操作之一:查找


查找(Searching)

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

/* 结构代码*/
typedef  struct 
{
    ELementType Element[MaxSize];
   int Length;
}StaticTable;

方法一:顺序查找

/*顺序查找,算法复杂度O(n)*/
int SequentialSearch (StaticTable *Tbl, ELementType K)
{
    /*在表Tbl[1]~Tbl[n]中查找关键字为K的数据元素*/
    int i;
    Tbl->Element[0] = K; /*建立哨兵*/
    for(i = Tbl->Length; Tbl->Element[i] != K;i--);
    return i;

哨兵的作用:

  1. 在边界设值即a[0];(a[0]=K)
  2. 循环查找若碰到这个值可退出循环,或到了边界也可退出循环;a[i]!=K;

方法二:二分查找法

/*二分查找法,效率为O(logN)*/

int BinarySearch (StaticTable *Tbl,ELementType K)
{
    /* 在表Tbl中查找关键字为K的数据元素;*/
    int left,right,mid,NoFound= -1;
    left = 1;           /*初始化左边界*/
    right = Tbl->Length;        /*初始化右边界*/
    while(left<=right)
    {
        mid = (left+right)/2; /*计算中间元素坐标*/
        if(K < Tbl->Element[mid])  
        right = mid-1;          /*调整右边界*/
        else if(K > Tbl->Element[mid]);         /*调整左边界*/
        else return mid; /*查找成功,返回数据元素的下标*/
    }
    return NotFound;     /*查找不成功,返回-1*/
}


2.二叉树

结构定义:

typedef struct TreeNode *BinTree;
struct  TreeNode{
    ELementType Data;
    BinTree Left;
    BinTree Right;
};

二叉树的遍历

先序遍历:

  1. 访问根节点;
  2. 先序遍历其左子树
  3. 先序遍历其右子树
    在这里插入图片描述
void PerpederTeaversal(BinTree BT)
{
if(BT){
    printf("%d",BT->Data);
    PerpederTeaversal(BT->Left);
    PerpederTeaversal(BT->Right);
    }
}

中序遍历:
1.中序遍历其左子树
2. 访问根节点;
3. 中序遍历其右子树
在这里插入图片描述

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

后序遍历:
在这里插入图片描述

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

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

二叉树的非递归遍历

即使用堆栈

中序遍历非递归遍历算法

  • 遇到一个结点,就把它压栈,并去遍历它的左子树;
  • 当左子树遍历结束后,从栈顶弹出这个结点并访问它;
  • 然后按其右指针再去中序遍历该结点的右子树。
/*二叉树的中序遍历非递归遍历算法*/

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

层次遍历

二叉树遍历的核心问题是:二维结构的线性化
而层次遍历可以同时遍历左,右结点。
储存结构:堆栈,队列
队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队,访问该结点,其左右结点入队。
在这里插入图片描述s
层序基本过程:先根结点入队,然后:

  1. 从队列中取出一个元素;
  2. 访问该元素所指结点;
  3. 若该元素所指结点的左,右孩子结点非空,则将其左右孩子的指针顺序入队。
void LevelOerderTraversal(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);   
    }
    }

3. 二叉搜索树

满足:在这里插入图片描述
例如:
在这里插入图片描述

二叉搜索树的查找操作:Find

  • 查找从根结点开始,如果树为空,返回NULL
  • 若搜索树非空,则根结点关键字和X进行比较,并进行不同处理:
  • 若X小于根结点键值,只需在左子树中继续搜索;
  • 若X大于根结点的键值,在右子树中进行继续搜索;
  • 若相等,搜索完成,return该值;

在这里插入图片描述

 /*二叉搜索树的查找操作*/
    Position IterFind(ELementType X,BinTree BST)
    {
        while(BST)
        {
            if(X > BST->Data)
            BST = BST->Right;
            else if(X < BST ->Data)
            BST = BST->Left;
            else /*X == BST->Data;*/
            return NULL;
        }
    }

查找最大和最小元素

/*查找最大值的迭代函数*/
    Position FinMax(BinTree BST)
    {
        if(BST)
        while(BST->Right)
        BST = BST->Right;
        /*沿右分支继续查找明知道最右叶结点*/
        return BST;
    }
    /*查找最小元素的递归函数*/
    Position FindMin(BinTree BST)
    {
        if(!BST) return NULL;
        else if (!BST->Left)
        return BST;
        else 
            return FindMin(BST->Left);
    }

二叉搜索树的插入

【分析】:关键是要找到元素应该插入的位置,可以采用与Find类似的方法

/*二叉搜索树的插入*/
    BinTree Insert(ELementType X,BinTree BST)
    {
        if (!BST)
        {/* 如原树为空,生成并返回一个结点的二叉搜索树*/
            BST = malloc(sizeof(struct TreeNode));
            BST->Data = X;
            BST->Left = BST->Right = NULL;
        }
        else /*开始找要插入元素的位置*/
            if(X<BST->Data)
            BST->Left = Insert(X,BST->Right);
                        /*递归插入左子树*/
            else if(X>BST->Data)
            BST->Right = Insert(X,BST->Right);
                        /*递归插入*子树*/
            return BST;
    }

二叉搜索树的删除

考虑三种情况

  • 要删除的是叶结点:直接删除,并再修改其父结点指针–置为NULL
  • 要删除的结点只有一个孩子结点:将其父结点的指针指向要删除结点的孩子结点
  • 要删除的结点有左,右两棵子树;用另一结点替代被删除结点:右子树的最小元素或左子树的最大元素
    /*二叉搜索树的删除*/
    BinTree Delete(ELementType X,BinTree BST)
    {
        Position Tmp;
        if(!BST) pintf("未找到");
        else if(X < BST->Data)
                BST->Left = Delete(X,BST->Left);/*左子树递归删除*/
        else if(X > BST->Right)
                BST ->Right = Delete(X,BST->Right);/*右子树递归删除*/
        else
             if(BST->Left && BST->Right){       /*被删除结点有左右两个子结点*/
                 Tmp = FindMin(BST->Right);
                                                /*在右子树中找最小的元素填充删除结点*/
                 BST->Data = Tmp->Data;
                 BST->Right = Delete(BST->Data,BST->Right);
                                                /*在删除结点的右子树删除最小元素*/
             }else{                     /*被删除结点有一个或无子结点*/
                 Tmp = BST;
                 if(!BST->Left)   /*有右孩子或无子结点*/
                 BST = BST->Right;
                 else if(!BST->Right)   /*有左孩子或无子结点*/
                 BST = BST-> Left;
                 free(Tmp);
             }
             return BST;
    }

学习来源

学习自中国mooc浙江大学的数据结构这一课程:
https://www.icourse163.org/learn/ZJU-93001?tid=120001#/learn/announce

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.墨白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值