1、重构二叉树:
(1)已知前序、中序,可以唯一确定一个二叉树;
(2)已知后序、中序,可以唯一确定一个二叉树;
(3)但是已知前序、后序却不能确定一棵二叉树;
(2)已知后序、中序,可以唯一确定一个二叉树;
(3)但是已知前序、后序却不能确定一棵二叉树;
2、二叉树操作相关:
/*二叉树数据结构*/
typedef struct bitree
{
int data;
struct bitree *l;
struct bitree *r;
}B_TREE_T;
/*创建操作*/
B_TREE_T* create(int *aa, int len)
{
int i = 0;
B_TREE_T * t = NULL;
for(i = 0;i < len;i++)
{
t = insert(t, aa[i]);
}
return t;
}
/*插入操作*/
B_TREE_T * insert(B_TREE_T *t, int key)
{
if(NULL == t)
{
t = (B_TREE_T* )malloc(sizeof(B_TREE_T));
t->l = NULL;
t->r = NULL;
t->data = key;
return t;
}
else if(key < t->data)
{
t->l = insert(t->l, key);
}
else
{
t->r = insert(t->r, key);
}
return t;
}
/*前序遍历*/
void first_v(B_TREE_T *t)
{
if(NULL == t)
return;
printf(" %d", t->data);
if(t->l)
first_v(t->l);
if(t->r)
first_v(t->r);
return;
}
/*中序遍历*/
void middle_v(B_TREE_T *t)
{
if(NULL == t)
return;
if(t->l)
middle_v(t->l);
printf(" %d", t->data);
if(t->r)
middle_v(t->r);
}
/*后序遍历*/
void after_v(B_TREE_T *t)
{
if(NULL == t)
return;
if(t->l)
after_v(t->l);
if(t->r)
after_v(t->r);
printf(" %d", t->data);
}
/*层次遍历*/
int level_v(B_TREE_T *t, int level)
{
if(NULL == t)
return 0;
if(0 == level)
{
printf(" %d", t->data);
return 1;
}
return level_v(t->l, level-1) + level_v(t->r, level-1);
}
/*查询操作*/
int search(B_TREE_T *t, int key)
{
if(NULL == t)
return 0;
if(key == t->data)
{
printf("Found it\n");
return 1;
}
if(key < t->data)
{
return search(t->l, key);
}
else
{
return search(t->r, key);
}
return 0;
}
/*树深度*/
int depth(B_TREE_T *t)
{
return t? max(depth(t->l), depth(t->r))+1 : 0;
}
/*翻转操作*/
B_TREE_T* reverse(B_TREE_T *t)
{
B_TREE_T *tmp;
if(NULL == t)
return NULL;
reverse(t->l);
reverse(t->r);
tmp = t->l;
t->l = t->r;
t->r = tmp;
}
/*删除操作*/
/*删除节点有如下几种情况:
1、若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。
由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。
2、若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)
或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
2、若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,
可按中序遍历保持有序进行调整,可以有两种做法:
(1)令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,
*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;
(2)令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)
即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
*/
int delete(B_TREE_T *t, int key)
{
B_TREE_T *q,*p = t;
int flag = 0;
while(p && !flag)
{
if(key == p->data)
{
flag = 1;
}
else if(key < p->data)
{
q = p;
p = p->l;
}
else
{
q = p;
p = p->r;
}
}
if(0 == flag)
return -1;
//no child
if(NULL == p->l && NULL == p->r)
{
if(p == t)
{
t = NULL;
}
else if(q->l == p)
{
q->l = NULL;
}
else
{
q->r = NULL;
}
free(p);
}
else if(NULL == p->l || NULL == p->r)
{
if(p == t)
{
if(NULL == p->l)
{
t = p->r;
}
else
{
t = p->l;
}
}
else
{
if(q->l == p && p->l)
{
q->l = p->l;
}
else if(q->l == p && p->r)
{
q->l = p->r;
}
else if(q->r == p && p->l)
{
q->r = p->l;
}
else
{
q->r = p->r;
}
}
free(p);
}
else
{
B_TREE_T *k = p;
B_TREE_T *s = p->l;
while(s->r)
{
k = s;
s = s->r;
}
p->data = s->data;
if(k == p)
{
p->l = s->l;
}
else
{
k->r = s->l;
}
free(s);
}
return flag;
}
/*根据前序、中序重建二叉树*/
B_TREE_T *constrcut1(int *pre, int *mid, int len)
{
int i = 0;
int data = pre[0];
B_TREE_T *tmp = NULL;
if(NULL == pre || NULL == mid || len <=0)
return NULL;
tmp = (B_TREE_T *)malloc(sizeof(B_TREE_T));
if(NULL == tmp)
{
printf("Failed to malloc tree node!\n");
return NULL;
}
tmp->data = data;
tmp->l = tmp->r = NULL;
for(i = 0;i
0)
tmp->l = constrcut1(&pre[1],&mid[0],lenL);
if(lenR > 0)
tmp->r = constrcut1(&pre[lenL+1], &mid[lenL+1], lenR);
return tmp;
}
/*非递归前序遍历*/
void first_order_nonrecursion(B_TREE_T *t)
{
B_TREE_T *p = root;
stack
s;
if (root == NULL)
return;
while (!s.empty() || p)
{
//边遍历边打印,并存入栈中,以后需要借助这些根节点(不要怀疑这种说法哦)进入右子树
while (p)
{
cout << setw(4) << p->data;
s.push(p);
p = p->lchild;
}
//当p为空时,说明根和左子树都遍历完了,该进入右子树了
if (!s.empty())
{
p = s.top();
s.pop();
p = p->rchild;
}
}
cout << endl;
}
/*非递归中序遍历*/
void mid_order_nonrecursive(B_TREE_T *t)
{
B_TREE_T *p = root;
stack
s;
if(NULL == t)
return;
while (!s.empty() || p)
{
//一直遍历到左子树最下边,边遍历边保存根节点到栈中
while (p)
{
s.push(p);
p = p->lchild;
}
//当p为空时,说明已经到达左子树最下边,这时需要出栈了
if (!s.empty())
{
p = s.top();
s.pop();
cout << setw(4) << p->data;
//进入右子树,开始新的一轮左子树遍历(这是递归的自我实现)
p = p->rchild;
}
}
}
/*非递归后序遍历*/
void last_order_nonrecursive(B_TREE_T T) // 后序遍历的非递归 双栈法
{
stack
s1 , s2;
B_TREE_T curr ; // 指向当前要检查的节点
s1.push(T);
while(!s1.empty()) // 栈空时结束
{
curr = s1.top();
s1.pop();
s2.push(curr);
if(curr->lchild)
s1.push(curr->lchild);
if(curr->rchild)
s1.push(curr->rchild);
}
while(!s2.empty())
{
printf("%c ", s2.top()->data);
s2.pop();
}
}
/*二叉树转换为排序链表*/
//tree -> list
//left -> prev
//right -> next
void convertNode(B_TREE_T *t, B_TREE_T **list)
{
B_TREE_T *cur = t;
if(NULL == t)
return;
if(NULL != cur->l)
convertNode(cur->l, list);
cur->l = *list;
if(NULL != *list)
(*list)->r = cur;
*list = cur;
if(NULL != cur->r)
convertNode(cur->r, list);
}
B_TREE_T *convert(B_TREE_T *t)
{
B_TREE_T *headlist;
B_TREE_T *list = NULL;
convertNode(t, &list);
headlist = list;
while(headlist != NULL && headlist->l != NULL)
headlist = headlist->l;
return headlist;
}
3、平衡二叉树
定义:平衡二叉树或为空树,或为如下性质的二叉排序树:
(1)左右子树深度之差的绝对值不超过1;
(2)左右子树仍然为平衡二叉树。
平衡因子BF=左子树深度-右子树深度.
平衡二叉树每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。
(1)左右子树深度之差的绝对值不超过1;
(2)左右子树仍然为平衡二叉树。
平衡因子BF=左子树深度-右子树深度.
平衡二叉树每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。
转发平衡二叉树:http://www.cnblogs.com/suimeng/p/4560056.html
4、红黑树
定义:满足如下性质的二叉排序树:
(1)每个结点要么是红的,要么是黑的。
(2)根结点是黑的。
(3)每个叶结点,即空结点(NIL)是黑的。
(4)如果一个结点是红的,那么它的俩个儿子都是黑的。
(5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
(1)每个结点要么是红的,要么是黑的。
(2)根结点是黑的。
(3)每个叶结点,即空结点(NIL)是黑的。
(4)如果一个结点是红的,那么它的俩个儿子都是黑的。
(5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。