文章目录
- 一.二叉树的概念
- 二.二叉树的遍历和线索二叉树(默认都为二叉链表存储)
- 1.编写后序遍历二叉树的非递归算法
- 2.试给出二叉树自下而上,从右到左的层次遍历算法.
- 3.用递归算法求二叉树的高度
- 4.用非递归算法求二叉树的高度(层次遍历)
- 5.求二叉树的宽度
- 6.建立二叉树的二叉链表
- 7.判定是否为完全二叉树
- 8.计算二叉树中所有双分支结点的个数
- 9.将二叉树的左右子树全部交换
- 10.求先序遍历的第k(1<=k<=二叉树中结点的个数)个结点的值
- 11.删去以每个元素值为x的根的结点的子树,并释放空间
- 12.查找所有值为x的结点,并打印这些结点的祖先
- 方法三:栈的基本操作
- 13.满二叉树已知先序序列求后序序列
- 14.二叉树的叶子结点按从左到右的顺序连成一个单链表
- 15.设计判断两个二叉树是否相似的算法
- 16.在中序线索二叉树里查找指定结点在后序的前驱结点
- 17.求带权路径长度
- 三.树和森林
- 四.哈夫曼树和哈夫曼编码
一.二叉树的概念
1.求两结点的最近公共祖先结点(二叉树任意两个结点必然存在最近的公共祖先结点)
已知一颗二叉树按顺序存储结构进行存储,设计一个算法,求编号分别为i和j的两个结点的最近公共祖先结点
方法一
思想
最坏的情况是:最近公共祖先结点为根节点,而且从最近的公共祖先结点到根节点的全部祖先结点都是公共的。由二叉树的顺序存储的性质可知,任意结点i的双亲结点的编号为i/2,求解i和j最近公共祖先结点的算法步骤如下(设从数组下标1开始存储)
(1)若i>j,则结点i所在层次大于等于结点j所在层次。结点i的双亲结点为i/2,
若i/2=j,则结点i/2是原结点i和结点j的最近公共祖先结点。
若i/2!=j,则令i=i/2,即以i的双亲结点为起点,采用递归的方法继续查找。
(2)若i<j,同理于(1)
代码
int Common(SqTree T,int i,int j)
{
//本算法在二叉树中查找结点i和结点j的最近公共祖先结点
if(T[i]!='#'&&T[j]!='#')
{
while(i!=j)
{
//两个编号不同时,循环
if(i>j)
i=i/2;//向上找i的祖先
else
j=j/2;//向上找j的祖先
}
return T[i];
}
}
方法二
思想:
后序遍历二叉树,根压在栈底,最后访问。设p在q的左边。采用后序非递归算法,栈中存放二叉树结点的指针,当访问到某结点时,栈s中所有元素均为该结点的祖先。
1.后序遍历先遍历到p
2.将栈复制到辅助栈s1
3.继续遍历到结点q时
4.s从栈顶开始逐个与s1中去匹配
5.第一个匹配的元素就是这俩结点的最近公共祖先。
代码:
//二叉树中求两个结点的祖父结点
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
#define MaxSize 50
typedef struct BiNode
{
char data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
typedef struct
{
BiTree t;
int tag;//tag=0表示左子女已被访问,tag=1表示右子女已被访问
}Bistack;//栈内存放二叉树结点
BiNode *FindBiNode(BiTree &T,char ch);
Bistack s[MaxSize],s1[MaxSize];
int top=0,top1;
BiNode *Ancestor(BiTree &T,BiNode *p,BiNode *q)
{
BiNode *bt=T;
while(bt!=NULL||top>0)
{
while(bt!=NULL)
{
if(bt!=p&&bt!=q)
{
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;
}
else
{
s[++top].t=bt;
s[top].tag=1;
break;
}
}
while(top!=0&&s[top].tag==1)
{
if(s[top].t==p)
{
if(bt->rchild!=NULL &&bt->lchild!=NULL){
BiNode *temp = FindBiNode(bt,q->data);
if(temp !=NULL){
return bt;
}
}
for(int i=1;i<=top;i++)
{
s1[i]=s[i];
top1=top;
}
}
else if(bt==q)
{
for(int i=top;i>0;i--)
{
for(int j=top1;j>0;j--)
{
if(s[i].t==s1[j].t)
{
return s[i].t;
}
}
}
}
top--;
}
if(top!=0)
{
s[top].tag=1;
bt=s[top].t->rchild;
}
}
return NULL;
}
void CreatBiTree(BiTree &T)
{
char ch;
cout<<"输入元素,按#结束:"<<endl;
cin>>ch;
if(ch=='#')
T=NULL;
else
{
T=new BiNode;
T->data=ch;
CreatBiTree(T->lchild);
CreatBiTree(T->rchild);
}
}
void PreOrder(BiTree &T)
{
if(T!=NULL)
{
cout<<T->data<<" ";
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//按值查找二叉树中结点
BiNode *FindBiNode(BiTree &T,char ch)//**~~~~~~~按值查找**
{
if(T==NULL)
return NULL;
if(T->data==ch)
return T;
BiNode *p=FindBiNode(T->lchild,ch);
if(p!=NULL)
return p;
return FindBiNode(T->rchild,ch);
}
int main()
{
BiTree T;
CreatBiTree(T);
cout<<"前序遍历结果:"<<endl;
PreOrder(T);
cout<<"输入结点值:"<<endl;
char ch;
cin>>ch;
BiNode *p=FindBiNode(T,ch);
if(p==NULL)
{
cout<<"无此结点"<<endl;
exit(0);
}
else
{
cout<<p->data<<endl;
cout<<"查找成功"<<endl;
}
cout<<"输入结点值:"<<endl;
char ch2;
cin>>ch2;
BiNode *q=FindBiNode(T,ch2);
if(q==NULL)
{
cout<<"无此结点"<<endl;
exit(0);
}else
{
cout<<q->data<<endl;
cout<<"查找成功"<<endl;
}
BiNode *res=Ancestor(T,p,q);
if(res!=NULL)
cout<<res->data<<endl;
else
cout<<res->data<<endl;
return 0;
}
二.二叉树的遍历和线索二叉树(默认都为二叉链表存储)
1.编写后序遍历二叉树的非递归算法
思想
后序:左右根的顺序.
1.沿着根的左孩子,依次入栈,直到左孩子为空。此时栈内元素依次为A,B,D
2.读栈顶元素:若其右孩子不为空且未被访问过,将右子树转执行1.
3.否则栈顶元素出栈并访问
每次出栈访问完一个结点就相当于遍历完以该结点为根的子树
代码
void PostOrder(BiTree T)
{
InitStack(S);//初始化栈
p=T;
r=NULL;//设定一个辅助指针r来指向最近访问过的结点
while(p||IsEmpty(S))
{
if(p)
{
push(S,p);
p=p->lchild;
}
else
{
//向右
GetTop(S,p);//读栈顶结点非出栈
if(p->rchild&&p->rchild!=r)
{
//若右子树存在,且未被访问过
p=p->rchild;//转向右