数据结构之树篇1——二叉树

性质

基本性质:二叉树_百度百科

关于二叉树的深度(高度)涉及到结点的层数,有的教材规定根结点在第\(0\)层,有的则规定根结点在第\(1\)层。

这里全部以《数据结构-C语言版》(严蔚敏,吴伟民版)为准:高度和深度为同一个概念,根节点在第1层,树的高度是看一共有几层。 高度为\(h\)的完全二叉树,最多有\(2^{n}-1\)个节点,第\(k\)层最多有\(2^{k-1}\)个节点。 含有\(n\)个节点的完全二叉树,高度为\(log(n)+ 1\)下取整。

完全二叉树:

如果第一个元素下标为\(1\),则第\(k\)个元素的左孩子为\(2*k\),右孩子为\(2*k+1\),父节点为 \(k / 2\) 下取整,最后一个父节点为 \(length / 2\) 下取整。

如果第一个元素下标为\(0\),则第\(k\)个元素的左孩子为\(2*k+1\),右孩子为\(2*k+2\),父节点为 \((k - 1)/ 2\) 下取整,最后一个父节点为 \(length / 2\) 下取整后减一。

二叉树的前驱后继节点,表示中序遍历时,一个节点的前一个和后一个。

高度为\(h\)的完全二叉树,最多有\(2^{h}-1\)个节点。

节点为\(n\)的完全二叉树,高度为\(log(n)\)

二叉树的遍历

二叉树的有三种遍历方式,先中后序遍历,“先、中、后”表示根节点的遍历次序

先序:先遍历分支的根节点,再遍历左子树,最后遍历右子树。

先序序列:\(ABDFECGHI\)

img

中序:先遍历分支的左子树,再遍历根节点,最后遍历右子树。

中序序列:\(DBEFAGHCI\)

img

后序:先遍历分支的左子树,再遍历右子树,最后遍历根节点。

后序序列:\(DEFBHGICA\)

img

二叉树遍历的实现

后序遍历非递归,是借用两个栈A,B,用A栈访问,压栈顺序为中左右(先序为中右左),把这些节点再存到B栈里,最后一起出栈。

//先序
void preorderUnRecur(BTree T) {
    stack<BTree>s;
    s.push(T);
    while (!s.empty()) {
        T = s.top();
        s.pop();
        cout << T->data << " ";
        if (T->Right)
            s.push(T->Right);
        if (T->Left)
            s.push(T->Left);
    }
    cout << endl;
}

//中序
void inorderUnRecur(BTree T) {
    if (!T)return;
    stack<BTree>s;
        while (!s.empty() || T) {
            if (T) {
                s.push(T);
                T = T->Left;
            }
            else {
                T = s.top(); s.pop();
                cout << T->data << " ";
                T = T->Right;
            }
        }
    cout << endl;
}

//后序

void postorderUnRecur(BTree T) {
    if (!T)return;
    stack<BTree>s1,s2;
    s1.push(T);
        while (!s1.empty()) {
            T = s1.top(); s1.pop();
            s2.push(T);
            if (T->Left)s1.push(T->Left);
            if (T->Right)s1.push(T->Right);
    }
        while (!s2.empty()) {
            cout << s2.top()->data << " ";
            s2.pop();
        }
    cout << endl;
}

递归实现,相比来说就比较简单了:

void Inorder(BTree t) {
    if (!t)return;
    Inorder(t->Left);
    cout << t->data << " ";
    Inorder(t->Right);
}
void Preorder(BTree t) {
    if (!t)return;
    cout << t->data << " ";
    Preorder(t->Left);
    Preorder(t->Right);
}
void Postorder(BTree t) {
    if (!t)return;
    Postorder(t->Left);
    Postorder(t->Right);
    cout << t->data << " ";
}

二叉树的构建

  二叉树的建立一般有两种方法:

(1)用数组的方式,或者一个个输入,按照节点的顺序,用一个特殊值(比如0,# )表示当前位置没有节点。但这样总归是会出现冲突的,比如某个节点的值就是0, # 的ASCII值。就不做写了。

(2)给定包含中序序列的两个序列。以下为 给定前序、中序序列时,创建二叉树。

通过包含中序序列(只有前后序列创建出的二叉树不唯一)的两个序列可以推出唯一的二叉树。

typedef struct BTNode
{
    int data;
    struct BTNode* Left;
    struct BTNode* Right;
}*BTree;

void PreAndInToPost(int* pre, int* in, int length) {
    if (length == 0) return;
    int rootIndex;
    BTree BT = new BTNode;
    BT->data = *pre;
    for (rootIndex = 0; in[rootIndex] != *pre; rootIndex++);
    PreAndInToPost(pre + 1, in, rootIndex);
    PreAndInToPost(pre + rootIndex + 1, in + rootIndex + 1, length - (rootIndex + 1));
    cout << BT->data << " ";
}

void PostAndInToPre(int* in, int* post, int length) {
    if (length == 0) return;
    int rootIndex;
    BTree BT = new BTNode;
    BT->data = *(post + length - 1);
    for (rootIndex = length - 1; in[rootIndex] != *(post + length - 1); rootIndex--);
    cout << BT->data << " ";
    PostAndInToPre(in, post, rootIndex);
    PostAndInToPre(in + rootIndex + 1, post + rootIndex, length - (rootIndex + 1));
}

完整测试代码如下:

#include <iostream>
using namespace std;

typedef char ElemType;

typedef struct BTNode
{
    ElemType data;
    struct BTNode* Left;
    struct BTNode* Right;
}*BTree;

BTree creat_tree_from_pre_inorder(ElemType* pre, ElemType* in, int length) {
    if (length == 0) return NULL;
    int rootIndex;
    BTree BT = new BTNode;
    //将当前根节点入树
    BT->data = *pre;
    for (rootIndex = 0; in[rootIndex] != *pre; rootIndex++);
    BT->Left = creat_tree_from_pre_inorder(pre + 1, in, rootIndex);
    BT->Right = creat_tree_from_pre_inorder(pre + rootIndex + 1, in + rootIndex + 1, length - (rootIndex + 1));
    return BT;
}
BTree creat_tree_from_post_inorder(ElemType* in, ElemType* post, int length) {
    if (length == 0) return NULL;
    int rootIndex;
    BTree BT = new BTNode;
    //将当前根节点入树
    BT->data = *(post + length - 1);
    for (rootIndex = length - 1; in[rootIndex] != *(post + length - 1); rootIndex--);
    BT->Left = creat_tree_from_post_inorder(in, post, rootIndex);
    BT->Right = creat_tree_from_post_inorder(in + rootIndex + 1, post + rootIndex/*删掉post的最后一个*/, length - (rootIndex + 1));

    return BT;
}


void Inorder(BTree BT) {
    if (!BT)return;
    Inorder(BT->Left);
    cout << BT->data << " ";
    Inorder(BT->Right);
}
void Preorder(BTree BT) {
    if (!BT)return;
    cout << BT->data << " ";
    Preorder(BT->Left);
    Preorder(BT->Right);
}
void Postorder(BTree BT) {
    if (!BT)return;
    Postorder(BT->Left);
    Postorder(BT->Right);
    cout << BT->data << " ";
}

int main() {
    char pre[] = "ABDGHCEIF";
    char in[] = "GDHBAEICF";
    char post[] = "GHDBIEFCA";
    BTree T1 = creat_tree_from_pre_inorder(pre, in, strlen(in));
    BTree T2 = creat_tree_from_post_inorder(in, post, strlen(in));
    Postorder(T1);
    cout << endl;
    Preorder(T1);
    cout << endl;
    return 0;
}

相关小算法

获取二叉树的深度

int height(BTree T) {
    if (T == NULL)
        return 0;
    int left = height(T->Left);
    int right = height(T->Right);
    return left >= right ? left + 1 : right + 1;
}

猜你喜欢

转载自www.cnblogs.com/czc1999/p/11768769.html