一:有关树的基本概念、
树也是一种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);
}
}