数据结构之二叉树

二叉树结构


1.递归思想

大学时期对递归一直不是很清晰,其实大部分情况下能通循环最好就使用循环,因为递归不断调用函数会导致程序运行效率下降。递归的有点在简化思路,程序员只需要考虑当前步骤需要做什么,我的理解中递归的实现需要的是可重复的步骤以及递归的终止条件,在实际情况中,很多问题用循环实现会很难实现,简单的例子就是快速排序算法,使用递归思路很简单,而使用循环。。。那可能还需要一个栈的数据结构存放节点。


前几天看到的找零问题就可以使用递归的思路,轻松解决问题。
题目是这样的:

小易准备去魔法王国采购魔法神器,购买魔法神器需要使用魔法币,但是小易现在一枚魔法币都没有,但是小易有两台魔法机器可以通过投入x(x可以为0)个魔法币产生更多的魔法币。
魔法机器1:如果投入x个魔法币,魔法机器会将其变为2x+1个魔法币 魔法机器2:如果投入x个魔法币,魔法机器会将其变为2x+2个魔法币
小易采购魔法神器总共需要n个魔法币,所以小易只能通过两台魔法机器产生恰好n个魔法币,小易需要你帮他设计一个投入方案使他最后恰好拥有n个魔法币。

只看算法部分:

def Exchange(target):
    if target==0:
        return
    elif target%2:
        target=(target-1)/2
        Exchange(target)
        print(1)
    else:
        target=(target-2)/2
        Exchange(target)
        print(2)

只需要从最后一步开始,每一步向前推进一个步骤,函数只需要考虑当前步骤需要做的事情即可。

2.二叉树的定义

二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。如果不考虑连通性,允许图中有多个连通分量,这样的结构叫做森林。

数据结构之二叉树_第1张图片

二叉树的五种基本形态
1. 空二叉树
2. 只有一个根节点
3. 根节点只有左子树
4. 根节点只有右子树
5. 根节点既有左子树又有右子树

3.二叉树相关性质


1. 在二叉树第i层上最多有2^(i-1)个节点。
2. 深度为k的二叉树最多有2^k-1个节点
3. 对于任何一个二叉树T,如果其终端节点数为n0,度为二的根节点数为n2则n0=n2+1
4. 具有n个节点的完全二叉树的深度为\log 2_n +1

4.二叉树的遍历

数据结构之二叉树_第2张图片

前序遍历
总是先查找根节点,之后查找左子树,最后查找右子树。(根左右)
上图按照前序遍历应该为:ABDEC

中序遍历
总是先查找左子树,再查找根,最后查找右子树。(左根右)
上图按照中序遍历就应该为:DBEAC

后序遍历
总是先查找左子树,再查找右子树,最后查找根节点。(左右根)
上图按照后序遍历就应该为:DEBCA

出了前序遍历和后序遍历的组合外,任意两个遍历方法值都能确定一个二叉树。

5.建立二叉树


因为一种遍历方式的值并不能唯一确定一个二叉树,所以需要用两种遍历值来确定,当然还有一种更简单的方法,空出来的节点用一个特殊字符表示,这里选择用’#’来表示空的节点。上图进行变换后应该如下图所示。
数据结构之二叉树_第3张图片
此时如果采用前序遍历那么结果应该是:ABD##E##C##,此时该二叉树是唯一确定的。


采用前序遍历的结果作为生成二叉树的依据。
**构建时采用递归思路,每一个步骤都是写入根节点,开辟左节点内存,右节点内存,进入左节点,进入右节点。
终止条件是:当该节点的值为’#’时,写入根节点,不再开辟左右几点内存,返回**

C/C++实现如下:

//节点类
class TreeNode
{
public:
    int date;
    TreeNode*LeftChild;
    TreeNode*RightChild;
};

二叉树类型:

class BiTree
{
public:
    TreeNode*Root;
    void CreateTree(TreeNode**ptr,int *s);
    int Deepth(TreeNode*ptr);
    BiTree(int*s);//构造函数 使用int数组来构造树
    int GetDeepth();//获得二叉树的深度
};

这里为了后面的搜索二叉树,存放的不再是字符(char类型)而换成了(int类型),-1代表空,也就是说将’#’换成-1。

构造方法:

BiTree::BiTree(int*s)
{
    Root = new TreeNode;
    CreateTree(&Root,s);
}

void BiTree::CreateTree(TreeNode**ptr, int*s)
{
    static int index = 0;
    if (s[index] == -1)
    {
        (*ptr)->date = -1;
        (*ptr)->LeftChild = NULL;
        (*ptr)->RightChild = NULL;
        index++;
    }
    else
    {//根左右的前序遍历方法
        (*ptr)->LeftChild = new TreeNode;
        (*ptr)->RightChild = new TreeNode;
        (*ptr)->date = s[index++];
        CreateTree(&(*ptr)->LeftChild, s);
        CreateTree(&(*ptr)->RightChild, s);
    }
}

该构造函数需要输入的int数组是正确符合前序遍历的,否则可能出现数组越界问题。


获取二叉树深度

int BiTree::GetDeepth()
{
    return Deepth(Root);
}

int BiTree::Deepth(TreeNode*ptr)
{
    if (ptr->date == -1)
    {
        return 0;
    }
    int nLeft = Deepth(ptr->LeftChild);
    int nRight = Deepth(ptr->RightChild);
    return nLeft > nRight ? nLeft + 1 : nRight + 1;
}

你可能感兴趣的:(数据结构,算法导论,数据结构,二叉树)