(4).AVL树:
使用了AVL树的插入,删除和查找。
数据结构即二叉树,多一个平衡因子(左右树深度的差值)的变元。
主要函数:void Lrotate(node * &p); //左旋
void Rrotate(node * &p); //右旋
void maintain(node * &p); //维护平衡
思路及原理:AVL树是一种平衡二叉树,其难点在于树平衡的维护。每当插入一个节点是,平衡因子会发生改变(原理是左右子树的深度差发生变化),当差值大于1时,需要平衡化。通过左旋,右旋,最后完成平衡。
(5).森林与二叉树的相互转化:
使用了邻接表存储结构,输入二叉树或森林实现森林向二叉树树的转化,和树向森林的转化。
结构如下:
typedef struct bnode//定义二叉树结点
{
char x;
struct bnode *lchild;
struct bnode *rchild;
} bnode;
typedef struct fnode //存储森林
{
int parent;
char x;
} fnode;
fnode f[30];
主要函数:
bnode * build(int i,int j,int u,int v,char pre[100],char in[100])//用递归方法建立二叉树
void ftob(bnode *b,int n); //森林转化为二叉树
void btof(bnode *b,int n); //二叉树转化为森林
思路及原理:先说二叉树转化为森林。链接所有二叉树的根节点和左右而知节点,再删去右儿子节点的连线和深度大于1的左儿子连线,即可得到森林。森林转化为二叉树的过程与之相对,通过遍历删连接线即可。
(6).前序/后序/层序遍历
使用了二叉链表存储结构,输入一个森林,进行三种遍历,输出遍历结果
结构如下:
struct FNode {
FNode *next;
FNode *parent;
FNode *child;
int weight;
int id;
};
思路及原理:其实就是左儿子右兄弟表示出来后的遍历算法。从某个节点为起始开始进行栈操作得到遍历即可。
AVL树的插入、删除、查找
/*
author:yjc
time:2014/3/21
title:AVL tree
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#define oo 0x7FFFFFFF
using namespace std;
template <typename T>
class AVL
{
private:
class node
{
public:
node *l,*r;
int h,size;
T dat;
node() : l(0) ,r(0), h(1),size(0) {};
node(T tdat) : dat(tdat),l(0),r(0), h(1),size(1) {};
//得到平衡因子
int geth()
{
if(!this) return 0;
else return h;
}
//得到子树深度
int getsize()
{
if(!this) return 0;
else return size;
}
//更新平衡后的树的高度
void update()
{
if(this)
{
h = max(l->geth() ,r->geth()) + 1;
size = l->getsize() + r->getsize() + 1;
}
}
}*root;
//左旋
void Lrotate(node * &p)
{
node * t = p->r->l;
p->r->l = p;
p= p->r;
p->l->r =t;
p->l->update();
p->update();
}
//右旋
void Rrotate(node * &p)
{
node * t = p->l->r;
p->l->r = p;
p= p->l;
p->r->l = t;
p->r->update();
p->update();
}
//维持平衡的操作
void maintain(node * &p)
{
int lh ,rh;
if(p->l->geth() > p->r->geth() + 1) // To balance the left tree
{
lh = p->l->l->geth();
rh = p->l->r->geth();
if(lh >= rh)
Rrotate(p);
else
{
Lrotate(p->l);
Rrotate(p);
}
}
if(p->r->geth() > p->l->geth() + 1 ) // To balance the right tree
{
lh = p->r->l->geth();
rh = p->r->r->geth();
if(rh >= lh)
Lrotate(p);
else
{
Rrotate(p->r);
Lrotate(p);
}
}
}
//插入操作
void insert(node * & p, T dat)
{
if(!p)
{
p = new node(dat);
return;
}
if(dat <= p->dat)
insert(p->l,dat);
else
insert(p->r,dat);
maintain(p);
p->update();
}
//删除操作
void erase(node * & p, T dat)
{
if(!p) return;
if(p ->dat == dat)
{
if(p->l && p->r)
{
node * t = p->r;
while(t->l)
t = t->l;
p->dat = t->dat;
erase(p->r,t->dat);
maintain(p);
}
else if(p->l)
{
p->dat = p->l->dat;
p->l = 0;
}
else if(p->r)
{
p->dat = p->r->dat;
p->r = 0;
}
else p = 0;
p->update();
return;
}
else if(dat < p->dat)
erase(p->l,dat);
else
erase(p->r,dat);
maintain(p);
p->update();
}
//查找操作
bool findk(node * p, int k)
{
if(!p) return false;
else if(k == p->dat)
return true;
else if(k <= p->dat)
return findk(p->l,k);
else if(k > p->dat)
return findk(p->r,k);
}
public:
AVL() : root(0) {};
void insert(T dat)
{
insert(root, dat);
}
void erase(T dat)
{
erase(root, dat);
}
bool findk(int k)
{
if(findk(root, k)) return true;
return false;
}
//清空操作
void clear(node * p)
{
if(!p)
return;
clear(p->l);
clear(p->r);
delete p;
}
//判空
bool empty()
{
return (root->getsize() == 0);
}
int size()
{
return root->getsize();
}
//得到根节点
node* getroot()
{
return root;
}
//打印操作,中序遍历
void print(node *p){
if(p!=NULL){
print(p->l);
printf("%d ",p->dat);
print(p->r);
}
}
};
int main()
{
int n,dat;
char cmd;
printf("请输入操作总数:");
while(scanf("%d",&n) == 1)
{
AVL <int> avl;
printf("操作类型和操作数(操作类型中'I'表示插入,'F'表查找,'D'表删除):");
while(n--)
{
scanf(" %c %d",&cmd,&dat);
if(cmd == 'I')
{
int tmp= avl.findk(dat);
if(tmp==1){
printf("The num is already in the AVL_tree\n");
continue;
}
avl.insert(dat);
printf("After adding: root=%d \n",avl.getroot()->dat);
printf("The Tree Searched by In order: ");
avl.print(avl.getroot());
cout << endl;
}
else if(cmd == 'F')
{
int tmp = avl.findk(dat);
printf("%s\n", tmp == 0 ? "No" : "Yes");
}
else if(cmd == 'D')
{
int tmp = avl.findk(dat);
if(tmp == 1){
avl.erase(dat);
printf("after Deleting: root=%d \n",avl.getroot()->dat);
printf("The Tree Searched by In order: ");
avl.print(avl.getroot());
cout << endl;
}
else{
printf("Not found the node.\n");
continue;
}
}
}
avl.clear(avl.getroot());
}
return 0;
}
/*
10
I 2
I 8
I 6
I 4
F 6
D 6
I 1000
F 93
D 1000
D 2
*/
邻接表实现树与森林的转换
/*
author:yjc
time:2014/3/22
title:邻接表存储实现森林与树的转换
*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef struct bnode//定义二叉树结点
{
char x;
struct bnode *lchild;
struct bnode *rchild;
} bnode;
typedef struct fnode
{
int parent;
char x;
} fnode;
fnode f[30];
bnode *BuildNode()//建立新结点
{
bnode *p;
p=(bnode *)malloc(sizeof(bnode));
p->lchild=NULL;
p->rchild=NULL;
return p;
}
bnode * build(int i,int j,int u,int v,char pre[100],char in[100])//用递归方法建立二叉树
{
int k,l;
bnode *head,*s;
head=NULL;
if(i<=j)//先根序列已结束
{
head=BuildNode();//建立根节点
head->x=pre[i];
k=u;
while(in[k]!=pre[i])
{
k++;//找到中序的根节点
}
l=i+k-u;//l为左子树中最右下节点在前序序列中的位置
if(k==u)//左子树为空
{
head->lchild=NULL;
}
else
{
s=build(i+1,l,u,k-1,pre,in);//构造左子树
head->lchild=s;
}
if(k==v)//右子树为空
{
head->rchild=NULL;
}
else
{
s=build(l+1,j,k+1,v,pre,in);//构造右子树
head->rchild=s;
}
}
return head;
}
void ShowTree(bnode *p)//输出创建的二叉树
{
if(p!=NULL)
{
printf("(");
printf("%c",p->x);
printf(",");
ShowTree(p->lchild);
printf(",");
ShowTree(p->rchild);
printf(")");
}
else printf("#");
}
void ftob(bnode *b,int n)
{
int a,i=1,j,k;
bnode *d[30];
b=BuildNode();
b->x=f[i].x;
d[i]=b;
i++;
while(f[i].parent==0)
{
b->rchild=BuildNode();
b=b->rchild;
b->x=f[i].x;
d[i]=b;
i++;
}
while(i<=n)
{
k=f[i].parent;
b=BuildNode();
b->x=f[i].x;
d[k]->lchild=b;
d[i]=b;
i++;
if(i>n)
{
break;
}
while(f[i].parent==k)
{
b->rchild=BuildNode();
b=b->rchild;
b->x=f[i].x;
d[i]=b;
i++;
if(i>n)
{
break;
}
}
}
}
void btof(bnode *b,int n)
{
int x=1,num,k,i;
bnode *d[30],*p;
if(b==NULL)
{
return ;
}
else
{
while(b!=NULL)
{
f[x].x=b->x;
f[x].parent=0;
d[x]=b;
x++;
b=b->rchild;
}
num=x;
k=1;
while(x<=n)
{
for(i=k; i<num; i++)
{
p=d[i]->lchild;
while(p!=NULL)
{
f[x].x=p->x;
f[x].parent=i;
d[x]=p;
x++;
p=p->rchild;
}
}
k=i;
num=x;
}
}
}
int main()
{
int c,num,i;
char pre[30],in[30];
bnode *p;
printf("请输入要创建树的结点数:");
scanf("%d",&num);
printf("请输入前序序列:");
scanf("%s",pre);
printf("请输入中序序列:");
scanf("%s",in);
p=build(0,num-1,0,num-1,pre,in);
btof(p,num);
ShowTree(p);
getch();
puts("\n***********************MENU*********************\n");
puts("1.二叉树转化为森林\n");
puts("2.森林转化为二叉树\n");
puts("3.结束转化\n");
puts("************************************************\n");
while(1)
{
printf("请输入你的选择(1-3): ");
while(1)
{
scanf("%d",&c);
if(c<1||c>3)
{
printf("出错了!请再次输入(1-3): ");
}
else
break;
}
switch(c)
{
case 1:
btof(p,num);
for(i=1; i<=num; i++)
{
printf("(%d)%d.%c\n",f[i].parent,i,f[i].x);
}
break;
case 2:
ftob(p,num);
ShowTree(p);
printf("\n");
break;
case 3:
exit(0);
break;
}
}
return 0;
}
/*
5
ABDCE
BDAEC
A
/ \
B C
\ /
D C
*/
二叉链表存储结构实现树的前序后序层序遍历
/*
author:yjc
time:2014/3/22
title:森林的遍历
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
#define maxn 1000
struct FNode {
FNode *next;
FNode *parent;
FNode *child;
int weight;
int id;
};
struct BNode {
BNode *parent;
BNode *lc,*rc;
int weight;
int id;
BNode() {
parent=lc=rc=NULL;
}
};
FNode F[maxn];
void InitF(int n) {
for(int i=1; i<=n; i++) {
F[i].id=i;
F[i].child=F[i].child=F[i].next=NULL;
}
}
BNode *Rt;
void Make1(BNode *rt,int x) {
FNode *tmp=F[x].child;
BNode *brt=rt;
if(tmp!=NULL) {
brt->lc=new BNode;
brt->lc->id=tmp->id;
brt->lc->parent=brt;
Make1(brt->lc,brt->lc->id);
tmp=tmp->next;
brt=brt->lc;
while(tmp!=NULL) {
brt->rc=new BNode;
brt->rc->id=tmp->id;
brt->rc->parent=brt;
Make1(brt->rc,tmp->id);
tmp=tmp->next;
brt=brt->rc;
}
}
}
void Print1(BNode *rt) {
if(rt==NULL) return;
Print1(rt->lc);
printf("id:%d lc:%d rc:%d\n",rt->id,rt->lc==NULL? 0:rt->lc->id,rt->rc==NULL? 0:rt->rc->id);
Print1(rt->rc);
}
char str[999];
BNode *PreBuild(BNode *rt){
int tmp;
cin>>tmp;
if(tmp) {
rt=new BNode;
rt->id=tmp;
rt->lc=PreBuild(rt->lc);
rt->rc=PreBuild(rt->rc);
}
else rt=NULL;
return rt;
}
void Make2(BNode *rt,BNode *pi){
if(rt==NULL) return;
printf("%d is %d's child.\n",rt->id,pi==NULL? 0:pi->id);
if(rt->lc!=NULL){
Make2(rt->lc,rt);
}
Make2(rt->rc,pi);
}
void PreP(BNode *rt){
if(rt==NULL) return;
printf("%d ",rt->id);
PreP(rt->lc);
PreP(rt->rc);
}
void PostP(BNode *rt){
if(rt==NULL) return;
PostP(rt->lc);
PostP(rt->rc);
printf("%d ",rt->id);
}
void LevelP(BNode *rt){
queue<BNode*> q;
q.push(rt);
while(!q.empty()){
BNode *cur=q.front();
q.pop();
printf("%d ",cur->id);
if(cur->lc!=NULL) q.push(cur->lc);
if(cur->rc!=NULL) q.push(cur->rc);
}
}
int main() {
printf("请输入选项(1:以森林形式输入 2:以二叉树形式输入):");
int cmd;
scanf("%d",&cmd);
if(cmd==1) {
int n,m;
printf("请输入顶点数:");
scanf("%d",&n);
InitF(n);
printf("请输入关系数:");
scanf("%d",&m);
int a,b;
for(int i=1; i<=m; i++) {
cin>>a>>b;
F[a].parent=&F[b];
FNode *tmp=F[b].child;
if(tmp==NULL) F[b].child=&F[a];
else {
while(tmp->next!=NULL){
tmp=tmp->next;
}
tmp->next=&F[a];
F[a].next=NULL;
}
}
Rt=NULL;
BNode *tmp=Rt;
for(int i=1; i<=n; i++) {
if(F[i].parent==NULL) {
if(Rt==NULL) {
Rt=new BNode;
Rt->id=i;
Rt->parent=NULL;
Rt->lc=NULL;
Rt->rc=NULL;
tmp=Rt;
} else {
tmp->rc=new BNode;
tmp->rc->parent=tmp;
tmp=tmp->rc;
tmp->id=i;
tmp->lc=tmp->rc=NULL;
}
Make1(tmp,i);
}
}
//Print1(Rt);
}else if(cmd==2){
printf("输入二叉的前序遍历序列(空节点用'0'表示): ");
Rt=PreBuild(Rt);
}
printf("前序遍历:\n");
PreP(Rt);
puts("");
printf("后序遍历\n");
PostP(Rt);
puts("");
printf("层序遍历\n");
LevelP(Rt);
puts("");
return 0;
}
/*
1
/ \
2 3
\ /
4 5
1
2
0
4
0
0
3
5
0
0
0
1
/ \
2 3
3
2
2 1
3 1
1------5
/ \ /
2 3 6
\
4
6
5
2 1
3 1
4 2
1 5
6 5
*/