一:有关树的基本概念、
树也是一种ADT结构,树可以有很多个儿子,当然每个节点除了根节点都有他们的父亲
某个节点的深度的含义是:该节点到根节点的最短距离,根节点的深度为0
某个节点的高度是指该节点到一片树叶的最长路径长

一般我们常研究的是二叉树
数据结构

struct treenode
{
    elementtype element;
    struct treenode left = NULL;
    struct treenode right = NULL;
};

二叉树的深度的平均值为logN
证明即为一般的等比数列求和

树遍历的四种方法
a:前序遍历

void print(treenode * T)
{
    if (T != NULL)
    {
        cout << T->element;
        print(T->left);
        print(T->right);
    }
}

b:中序遍历,与前序遍历类似,只不过打印的顺序为左根右
c:后续遍历,同样类似,打印顺序左右根
中间还有些小学问要注意,在此不方便描述
d:层序遍历

void print(treenode* T)
{
    auto m = new treenode*[1000];
    int i = 0;
    int j = 0;
    int last = 0;
    m[0] = T;
    while (j <= i)
    {
        last = i;
        while (j <= last;)
        {
            cout << m[i]->element;
            if (m[i]->left != NULL)
                m[++j] = m[i]->left;
            if ((m[i]->right != NULL)
                m[++j] = m[i]->right;
            ++i;
        }
        cout << endl;
    }
}

如何构造一棵表达式树
首先表达式要为逆波兰表达式,然后如果就是数字就直接压入栈,如果是符号则弹出两个栈组成一棵树再压入

二叉查找树
规则:对于每个节点,他的左子树中所有的关键字的值小于他本身的,又子树中的所有关键字的值大于他本身
插入例程

treenode* insert(int x, treenode* T)
{
    if (T == NULL)
    {
        T = new treenode;
        T->elemment = x;
    }
    else
    {
        if (x < T->element)
            T->left = insert(x, T->left);
        if (x > T->element)
            T->right = insert(x, T->right);
    }
    return T;
}

删除例程
有两种情况
1:该节点只有一个儿子,则直接用该儿子替代自己
2:该节点有两个儿子,则用右子树的最小数来代替该节点,递归删除右子树的最小数

treenode* delete1(int x, treenode* T)
{
    if (T == NULL)
    {
        cerr << "not found";
        return;
    }
    else
    {
        if (x < T->element)
            T->left = delete1(x, T->left);;
        else
            if (x > T->element)
                T->righy = delete1(x, T->right);
            else
            {
                if (T->left&&T->right)
                {
                    auto temp = findmin(T->right)->element;
                    T->date = temp;
                    T->right = delete1(temp, T->right);
                }
                else
                {
                    auto temp = T;
                    if (T->left == NULL)
                        T = T->right;
                    if (T->right == NULL)
                        T = T->left;
                    delete[] temp;
                }
            }
    }
    return T;
}

该树的平均深度为O(logN)
至于证明,我还没看到

该算法的问题所在:该删除算法最后左子树会很长,而右子树会很短
解决方法:通过随机选取左子树的最大值或者右子树的最小值来代替,或者交换进行

avl树
特征:左右子树的高度差最多为1
高度为h的avl中,最少节点数S(h)=S(h-1)+S(h-2)+1给出

struct avltree
{
    elementtype element;
    avltree* left = NULL;
    avltree* right = NULL;
    int height = -1;
};

int heightnum(avltree* T)
{
    return T->height;
}

单旋转

avltree* singlerationleft(avltree* T)
{
    auto k1 = T;
    auto k2 = T->left;
    k1->left = k1->right;
    k2->right = k1;
    return k2;
}

avltree* singlerationright(avltree* T)
{
    auto k1 = T;
    auto k2 = T->right;
    k1->right = k2->left;
    k2->left = k1;
    return k2;
}

avltree* doublerationleft(avltree* T)
{
    auto k1 = T;
    auto k2 = T->left;
    k2 = singlerationright(k2);
    return siglerationleft(k1);
}
avltree* doublerationright(avltree* T)
{
    auto k1 = T;
    auto k2 = T->right;
    k2 = singlerationleft(k2);
    return singlerationright(k1);
}

avltree* insert(int x, avltree* T)
{
    if (T == NULL)
    {
        T = new avltree;
        T->element = x;
    }
    else
    {
        if (x < T->element)
        {
            T->left = insert(x, T->left);
            if (heightnum(T->left)-heightnum(T->right)==2&&T->left < x)
            {
                T = doublerationleft(T);
            }
            else
            {
                if (heightnum(T->left) - heightnum(T->right) == 2 && T->left > x)
                    T = singlerationleft(T);
            }
        }
        else
        {
            if (x > T->element)
            {
                T->right = insert(x, T->right);
                if (heinum(T->right) = heightnum(T->left) == 2 && T->right < x)
                    T = singlerationright(T);
                else
                    if (heinum(T->right) = heightnum(T->left) == 2 && T->right > x)
                        T = doublerationright(T);
            }
        }
    }
    T->height = max(heightnum(T->left), heightnum(T->right)) + 1;
    return T;
}

伸展树
思想:由于普通的二叉查找树会使得树的结构变得很烂,例如如果1在底层,则此时我们如果要find(1),我们则需要遍历很深的树,并且如果1经常要被find则浪费的时间
更多了,所以我们将1提到根位置
两种提法:之字形,一字型

伸展树的神奇例程(当初楞生生的看了一个小时才看懂,我相信你们也一样[奸笑])

treenode* splay(int x, treenode* tree)
{
    treenode N, *c, *l, *r;
    if (tree == NULL)
        return;
    n = new treenode;
    l = r&N;
    for (;;)
    {
        if (x < tree->element)
        {
            if (tree->left == NULL)
                return;
            if (x<tree->left)
            {
                c = tree->left;
                tree->left = c->right;
                c->right = tree;
                tree = c;
                if (tree->left == NULL)
                    return;
            }
            r->left = tree;
            r = tree;
            tree = tree->left;
        }
        else
        {
            if (tree->right == NULL)
                return;
            if (x > tree->element)
            {
                if (tree->right->element < x)
                {
                    c = tree->right;
                    tree->right = c->left;
                    c->left = tree;
                    tree = c;
                    if (tree->right == NULL)
                        return;
                }
                l->right = tree;
                l = tree;
                tree = tree->right;
            }
            else
            {
                break;
            }
        }
        l->right = tree->left;
        r->left = tree->right;
        tree->left = N.right;
        tree->right = N.left;
    }
}

avl树的非递归插入操作

void insert(int x, avltree* root)
{
    auto temp = root;
    if (temp == NULL)
    {
        temp = new avltree;
        temp->element = x;
        return;
    }
    else
    {
        while (temp != NULL)
        {
            if (temp->element > x)
            {
                temp->left->height++;
                if (heightnum(temp->left) - heightnum(temp->right) == 2 && x < temp->left)
                    singlerationleft(temp);
                else
                {
                    if (heightnum(temp->left) - heightnum(temp->right) == 2 && x > temp->left)
                        doublerationleft(temp);
                }
                temp = temp->right;
            }
            else
            {
                if (temp->element < x)
                {
                    temp->right->height++;
                    if (heightnum(temp->right) - heightnum(temp->left) == 2 && x < temp->right)
                        doublerationright(temp);
                    else
                    {
                        if (heightnum(temp->right) - heightnum(temp->left) == 2 && x > temp->right)
                            singlerationright(temp);
                    }
                    temp = temp->right;
                }
            }
        }
    }
}

设二叉树的根结点的层次为1, 则高度为h的平衡二叉树的最少结点数为:
对于 h >= 1, N(h) = F(h + 2) - 1, 其中F(n) 为Fibonacci序列的各项:1, 1, 2, 3, 5, 8, 13.

N个节点的二叉树中,有N + 1个NULL指针
证明:
N个节点,就有2N个儿子指针,但由于根是没有儿子指针指向它的,故有2N - (N - 1) = N + 1个NULL指针

满节点是具有两个儿子的节点,证明满节点个数 + 1等于非空二叉树的树叶个数
证明:
设n0为无儿子的节点个数
n1为有一个儿子的节点个数
n2为有两个儿子的节点个数
总数 = n0 + n1 + n2 = 1(根)+n1 + 2n2
n0 = 1 + 2n2;

随机二叉树的深度平均为O(Logn)

avl树的非惰性删除
//删除之后左边比右边深,如果height(m->left)>=height(m->right)用单旋转
//如果height(m->left)

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

struct avltree
{
    avltree* left = NULL;
    avltree* right = NULL;
    int height;
    int date;
};

int height(avltree* m)
{
    if (m)
        return m->height;
    else
        return -1;
}

avltree* singlerationleft(avltree* m)
{
    auto k = m->left;
    m->left = k->right;
    k->right = m;
    m->height = max(height(m->left), height(m->right));
    k->height = max(height(k->left), height(k->right));
    return k;
}

avltree* singlerationright(avltree* m)
{
    auto k = m->right;
    m->right = k->left;
    k->right = m;
    m->height = max(height(m->left), height(m->right));
    k->height = max(height(k->left), height(k->right));
    return k;
}

avltree* doublerationleft(avltree* m)
{
    auto k1 = m->left;
    auto k2 = m->right;
    k2 = singlerationright(k2);
    return singlerationleft(m);
}

avltree* doublerationright(avltree* m)
{
    m->right = singlerationleft(m->right);
    return singlerationright(m);
}

avltree* insert(avltree* m, int x)
{
    if (m == NULL)
    {
        m = new avltree;
        m->date = x;
    }
    else
    {
        if (x > m->date)
        {
            m->right = insert(m->right, x);
            if (height(m->right) - height(m->left) == 2)
            {
                if (x > m->right->date)
                    m->right = singlerationright(m->right);
                else
                    m->right = doublerationright(m->right);
            }
        }
        else
        {
            if (x < m->date)
            {
                m->left = insert(m->left, x);
                if (height(m->left) - height(m->right) == 2)
                {
                    if (x < m->left->date)
                        m = singlerationleft(m);
                    else
                        m = doublerationleft(m);
                }
            }
        }
    }
    m->height = max(height(m->left), height(m->right)) + 1;
    return m;
}

avltree* findmin(avltree* m)
{
    auto x = m;
    while (x->left)
        x = x->left;
    return x;
}
avltree* delete1(avltree* m, int x)
{
    if (m->date < x)
    {
        m->left = delete1(m->left, x);
        if (height(m->right) - height(m->left) == 2 && height(m->right->right) >= height(m->right->left))
            m = singlerationright(m);
        else
            if (height(m->right) - height(m->left) == 2 && height(m->right->right) < height(m->right->left))
                m = doublerationright(m);
    }
    else
    {
        if (m->date > x)
        {
            m->right = delete1(m->right, x);
            if (height(m->left) - height(m->right) == 2 && height(m->left->left) >= height(m->left->right))
                m = singlerationleft(m);
            else
                if (height(m->left) - height(m->right) == 2 && height(m->left->left) < height(m->left->right))
                    m = doublerationleft(m);
        }
        else
        {
            if (m->left&&m->right)
            {
                m->date = findmin(m->right)->date;
                m->right = delete1(m->right, m->date);
            }
            else
            {
                auto temp = m;
                if (m->left == NULL)
                    m = m->right;
                else
                {
                    if (m->right == NULL)
                        m = m->left;
                }
                delete temp;
            }
        }
    }
    m->height = max(height(m->left), height(m->right));
    return m;
}

计算二叉树中T中节点, 树叶,满节点的个数

nt left = 0;
int node = 0;
int twochild=0

void count(treenode* T)
{
    if (T == NULL)
    {
        return;
    }
    if (T->leftchild&&T->rightchild)
    {
        node++;
        twochild++;
        count(T->right);
        count(T->right);
    }
    else
    {
        if (T->leftchild)
        {
            node++;
            count(T->leftchild);
        }
        else
        {
            if (T->rightchild)
            {
                node++;
                count(T->right);
            }
            else
            {
                node++;
                leaf++;
                count(T->left);
            }
        }
    }
}



二插线索树
struct treenode
{
    treenode* lchild;
    treenode* rchild;
    bool ltag = 0;
    bool rtag = 0;
};
treenode*  pre; //用来指向刚刚访问过的节点

void xiansuo(treenode* T)//中序遍历就是左根右
{
    if (T)
    {
        xiansuo(T->lchild);
        if (T->lchild == NULL)
        {
            T->ltag = 1;
            T->lchild = pre;
        }
        if (pre->rchild == NULL)
        {
            pre->rtag = 1;
            pre->rchild = T;
        }
        pre = T;
        xiansuo(T->rchild);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值