码迷,mamicode.com
首页 > 其他好文 > 详细

二叉树性质和有关操作汇总

时间:2015-05-10 20:33:27      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:二叉树建立   二叉树遍历   二叉树路径   

二叉树是一种重要的数据结构. 

二叉树是n(n>=0)个结点的有限集合,该集合或为空集,或由一个根结点和两棵互不相交的,分别称为根结点的左子树和右子树的二叉树组成(递归定义)

满二叉树:对于这样的一棵二叉树,如果所有分支结点都存在左右子树,且所有叶子节点都在同一层上,称这样的二叉树为满二叉树。

完全二叉树:如果一棵具有n个结点的二叉树的结构与满二叉树的前n个结点完全相同,称之为完全二叉树。

二叉树的性质:

性质1 二叉树的第i层结点数目最多为2^(i-1) (i>=1)

性质2 深度为k的二叉树至多有2^(k-1)

性质3 对于任意一棵二叉树,叶子结点(度为0)数为n0,度为2的结点个数为n2,则有n0=n2+1. 

证明:n0+n1+n2=n1+2*n2+1 即结点数=分支数+1

二叉树存储结构

1.顺序存储结构 (可用数组表示)适用于满二叉树,完全二叉树,否则会有大量空间浪费

2链式存储结构 数据域+左右孩子指针表示 数据域+左右孩子指针表示+双亲指针表示

二叉树的数据域+左右孩子指针表示 还可以推广到每个结点的孩子数至多为常数k的任意类型的树,但实际中若不是所有结点都有k个孩子,则会造成空间浪费。一种巧妙的方法用来表示孩子数任意的树-----左孩子右兄弟表示法,该方法对于任意n个结点的树,只需要O(n)的存储空间。下面以二叉树的链式存储结构: 数据域+左右孩子指针表示法为例 进行二叉树的相关操作。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define maximum 20

typedef struct BiTNode
{
	char data;
	struct BiTNode *lchild,*rchild;
}BTNode ;
typedef BTNode *BTree;

struct
{
	int ln;//节点的层次编号
	BTree p;//节点指针
}Qu[maximum];

//输入先序序列,创建二叉树的二叉链表
BTree CreateBTree()
{
	char ch;
	BTree T;
	if((ch=getchar())=='#')
		return(NULL);
	else
	{
		T=(BTNode *)malloc(sizeof(BTNode));
		T->data=ch;
		T->lchild=CreateBTree(T->lchild);//构造左子树
		T->rchild=CreateBTree(T->rchild);//构造右子树
		return (T);
	}	
}

//根据前序遍历和中序遍历构建二叉树
BTree CreateTreeByPreIn(char *preorder,char *inorder,int length)
{
	BTree root;
	int rootIndex=0;
	if(0==length)
		return NULL;
	root = (BTNode *)malloc(sizeof(BTNode));
	root->data = *preorder;
	for(;rootIndex<length;rootIndex++)
	{
		if(inorder[rootIndex]==*preorder)
			break;
	}
	root->lchild = CreateTreeByPreIn(preorder+1,inorder,rootIndex);
	root->rchild = CreateTreeByPreIn(preorder+rootIndex+1,inorder+rootIndex+1,length-rootIndex-1);
	return root;
}

//先序遍历
void preorder(BTree root)
{
	if(root!=NULL)
	{
		printf("%c",root->data);
		preorder(root->lchild);
		preorder(root->rchild);
	}
}

//先序遍历的非递归算法
void preorder1(BTree root)
{
    //BTNode *St[MaxSize],*p;
	BTree St[maximum],p;
    int top=-1;
    if(root!=NULL)
    {
        top++;//根结点入栈
        St[top]=root;
        while(top>-1)//桟不为空时循环
        {
            p=St[top];//退桟并访问该结点
            top--;
            printf("%c",p->data);
            if(p->rchild!=NULL)//右孩子入桟----顺序:先右再左入栈,出栈相反
            {
                top++;
                St[top]=p->rchild;
            }
            if(p->lchild!=NULL)//左孩子入桟
            {
                top++;
                St[top]=p->lchild;
            }
        }
        printf("\n");
    }
}

//中序遍历
void inorder(BTree root)
{
	if(root)
	{
		inorder(root->lchild);
		printf("%c",root->data);
		inorder(root->rchild);
	}
}

//中序遍历的非递归算法
void inorder1(BTree root)
{
    //BTNode *St[MaxSize],*p;
	BTree St[maximum],p;
    int top=-1;
    if(root!=NULL)
    {
		p=root;
        while(top>-1||p!=NULL)//桟不为空时循环
        {

            while(p!=NULL)//入桟
            {
                top++;
                St[top]=p;
				p=p->lchild;
            }
			if(top>-1)
			{
				p=St[top];
				top--;
			printf("%c",p->data);
			p=p->rchild;
			}
        }
        printf("\n");
    }
}

//后序遍历
void postorder(BTree root)
{
	if(root)
	{
	postorder(root->lchild);
	postorder(root->rchild);
	printf("%c",root->data);
	}
}

//后序遍历非递归算法
void postorder1(BTree root)
{
	BTree St[maximum],p;
    int flag,top=-1;
    if(root!=NULL)
    {
		do
		{
			while(root!=NULL)
			{
				top++;
				St[top]=root;
				root=root->lchild;
			}
			p=NULL;//p指向当前节点的前一个访问的节点
			flag=1;//设置b的访问标记为已访问过
			while(top!=-1&&flag)
			{
				root=St[top];//取出当前的栈顶元素
				if(root->rchild==p)//右子树不存在或已被访问,访问之
				{
					printf("%c",root->data);
					top--;
					p=root;//p指向刚被访问的节点
				}
				else
				{
					root=root->rchild;
					flag=0;//设置未被访问的标记
				}
			}
		}while(top!=-1);
        printf("\n");
    }
}
 
//层次遍历
void travelevel(BTree root)
{
	BTree Qu[maximum];
	int front,rear;
	front=rear=0;
	if(root!=NULL)
		printf("%c",root->data);
	rear++;
	Qu[rear]=root;
	while(rear!=front)
	{
		front=(front+1)%maximum;
		root=Qu[front];
		if(root->lchild!=NULL)
		{
			printf("%c",root->lchild->data);
			rear=(rear+1)%maximum;
			Qu[rear]=root->lchild;
		}
		if(root->rchild!=NULL)
		{
			printf("%c",root->rchild->data);
			rear=(rear+1)%maximum;
			Qu[rear]=root->rchild;
		}
	}
}

//统计二叉树叶子节点个数
int leaf_num(BTree root)
{
	int L,R;
	if(root==NULL)
		return 0;
	if(root->lchild==NULL&&root->rchild==NULL)
		return 1;
	L=leaf_num(root->lchild);
	R=leaf_num(root->rchild);
	return L+R;
}

//统计二叉树深度
int BTheight(BTree root)
{
	int l_height,r_height;
	if(root==NULL)
		return 0;
	else
	{
		l_height=BTheight(root->lchild);//左子树深度+1(根节点)
		r_height=BTheight(root->rchild);
		return l_height>r_height?(l_height+1):(r_height+1);
	}
}

//统计二叉树宽度
int BTwidth(BTree root)
{
	int front,rear;
	int num,max,i,n;
	front=rear=0;
	if(root!=NULL)
	{
		rear++;
		Qu[rear].p=root;//根节点入队
		Qu[rear].ln=1;//根节点层次编号1
		while(front!=rear)
		{
			front++;
			root=Qu[front].p;//队头出队
			num=Qu[front].ln;
			if(root->lchild!=NULL)
			{
				rear++;
				Qu[rear].p=root->lchild;
				Qu[rear].ln=num+1;
			}
			if(root->rchild!=NULL)
			{
				rear++;
				Qu[rear].p=root->rchild;
				Qu[rear].ln=num+1;
			}
		}
			max=0;num=1;i=1;
			while(i<=rear)//通过比较相同层次的节点数求数的宽度
			{
				n=0;
				while(i<=rear&&Qu[i].ln==num)
				{n++;i++;}
				num=Qu[i].ln;
				if(n>max)
					max=n;
			}
			return max;
	}
	else
		return 0;

}

//输出每个从根节点到叶子节点的路径
void printArray(char a[],int len)
{
	int i;
	for(i=0;i<len;i++)
		printf("%c",a[i]);
	printf("\n");
}

void printAllPath(BTree root,char path[],int pathLen)
{
	if(root == NULL)
		return;
	path[pathLen] = root->data;
	pathLen++;
	if(root->lchild == NULL && root->rchild == NULL)
		printArray(path,pathLen);
	else
	{
		printAllPath(root->lchild,path,pathLen);
		printAllPath(root->rchild,path,pathLen);
	}
} 

void printPaths(BTree root)
{
	char path[100];
	printAllPath(root,path,0);
}

//二叉树镜像--每个节点的左右子树都交换了的。
BTree exchange2(BTree T)
{	
	BTree temp;
	if(T)
	{	
		temp=T->lchild;	    
		T->lchild=T->rchild;	    
		T->rchild=temp;
		exchange2(T->lchild);
		exchange2(T->rchild);
	}
	return T;
}
//比较两棵二叉树是否相等
int CompareBTree(BTree root1,BTree root2)
{
	if(root1==NULL && root2==NULL)
		return 1;
	else if((root1==NULL&&root2!=NULL)||(root2==NULL&&root1!=NULL))
		return 0;
	else if(root1->data == root2->data)
	{
		if(CompareBTree(root1->lchild,root2->lchild) == 1)
			return CompareBTree(root1->rchild,root2->rchild);
	}
}

void main()
{
	BTree root1,root2;
	//int height,width;
	char pre_order[6]={'A','B','D','C','E','F'};
	char in_order[6]={'B','D','A','E','F','C'};
	printf("******************************************");
	printf("\n按先序遍历和空节点#建立二叉树:");
	root1 = CreateBTree();

	printf("\n先序遍历-递归root1:");
	preorder(root1);

	printf("\n先序遍历-非递归root1:");
	preorder1(root1);

	printf("\n中序遍历-递归root1:");
	inorder(root1);

	printf("\n中序遍历-非递归root1:");
	inorder1(root1);

	printf("\n后序遍历-递归root1:");
	postorder(root1);

	printf("\n后序遍历-非递归root1:");
	postorder1(root1);

	printf("\n层次遍历");
	travelevel(root1);
	
	printf("\n二叉树高度和宽度和叶子节点个数:");
	printf("%d,%d,%d",BTheight(root1),BTwidth(root1),leaf_num(root1));
	
	printf("\n输出二叉树所有路径:\n");
	printPaths(root1);
	printf("\n******************************************");
	printf("\n按先序遍历结果和中序遍历结果建立二叉树");
	root2 = CreateTreeByPreIn(pre_order,in_order,6);

	printf("\nroot1和root2是否相等:");
	if(CompareBTree(root1,root2)==1)
		printf("root1 == root2\n");
	else
		printf("root1 != root2\n");
}


技术分享

技术分享



参考:http://blog.csdn.net/sunmenggmail/article/details/7466635


二叉树性质和有关操作汇总

标签:二叉树建立   二叉树遍历   二叉树路径   

原文地址:http://blog.csdn.net/u010498696/article/details/45619951

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!