初探二叉树

                                                                               数据结构之初探二叉树

      树的一些基本概念:

               树:N个节点组成的有限集合(N>=0)。

               子树:上一个根节点的孩子,并且也是下一层子树的根节点。

               二叉树:最多只有两个孩子节点的树。

               空树:没有子节点的树。

               非空树:

                     树中至少有一个节点——根。

                     树中各子树是互不相交的集合。

        树的表示方法:

                   嵌套集合表示法,广义表法,凹入表示法。

        树的基本术语:

                   结点:表示树中的元素,包括数据项及若干指向其子树的分支。

                   结点的度:结点拥有的子树个数。

                   叶子结点:度为0的结点。

                   树的度:一颗树中最大的结点度数(子树数)。

   孩子:结点的子树的根称为该结点的孩子(结点)。

                   双亲:孩子结点的上一层结点叫该结点的父节点。

   兄弟:同一双亲的孩子互称兄弟(结点)。

                   结点的层次 :从根节点算起根为第一层。

                   树的深度 :树中结点的最大层次数。

                   堂兄弟:其双亲在同一层的结点互称为堂兄弟

                   结点的祖先:从根节点到该结点所经分支上的所有结点。

                   结点的子孙:以某根节点为根的子树中的任一结点叫之。

                   有序树:树中各结点的子树从左到右有次序(不能互换)。

                     森林:

                                 多棵互不相交的树构成的集合。

                        树


                例如这就是一棵二叉树。

                  二叉树的基本特征:

                          1.每个结点最多只有两棵子树。

                          2.子树有左右之分,其次序不能任意颠倒,是一个有序树。

         二叉树的几个基本性质:

                    一。

在二叉树的第i层上至多有2^(i-1)次方个结点。

     二。

                                深度为k的二叉树上至多含2^k-1个结点。

                     三。

                                 对任何一棵二叉树,若它含有N个叶子节点,N1个度为2的结点,则N=N1+1;

                      四。

                                  具有N个结点的完全二叉树的深度为:

                                          log2N(取整)+1.

                     五。

                                对于含有N个结点的完全二叉树从上到下且从左至右进行1至N的编号,则对完全二叉树中的任意一个编号为i的结点。

                               若i=1,该结点是二叉树的根,无双亲;否则编号为i/2向上取整的结点为其双亲。

                               若2i>n,  则该结点无左孩子,否则编号为2i的结点无右孩子结点,否则,编号为2i+1的结点为其右孩子结点,

                               若2i+1>n,则该结点无右孩子结点,否则编号为2i+1的结点为其右孩子结点。

                 

          满二叉树:

                          指的是深度为K且含有2^(k)-1个结点的二叉树。

           特点:每一层的结点树都是最大结点数

                  性质:第i层上至多有2^(i-1)个结点。

                  性质:深度为K的二叉树至多有2^k-1个结点。

            

         完全二叉树:

                        若一棵二叉树中所含的N个结点与满二叉树中编号为1至N的结点一一对应(编号和位置一一对应)。

                    特点:

                              1.叶子节点只可能在层次最大的两层上出现。

                               2.对任一结点,若其右分支下子孙的最大层次为1.则其左分支下子孙的最大层次必为1或1+1.

                


              下面将附上用二叉链表的方式建立二叉树,并且用#占位,显示先中后三种遍历方式:


                    

/*************************************************************************
	> File Name: mytree.c
	> Author: zmr
	> Mail: 1797763610@qq.com
	> Created Time: Sun 03 May 2015 02:46:57 PM CST
 ************************************************************************/

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
#define PE '#'

typedef struct tree{           //定义树结点结构 
	char ele;
	char nous[3];            //由与内存对齐问题先用数组占位 
#ifndef SYSTEM32
	char nouse[4];
#endif  
	struct tree *lchd,*rchd;
}_tree;

typedef struct quenode{             //队列结点 
	_tree *root;
	struct quenode *next;
}_que;


typedef struct nodectl{            //队列控制结构 
	_que *head,*tail;
	int lenth;
}_quectl;


typedef struct treectl {           //树的控制结构 
	_tree *root;
	int  nodes;
#ifndef SYSTEM32
	char nous[4];
#endif
}_treectl;

enum { CMD=0,STR };

void inq(_quectl *qctl,_tree *tree)      //队列的入队操作 
{
	_que * qnode = NULL;
	if(NULL == qctl || NULL == tree){
		return ;
	}
	qnode = (_que*)malloc(sizeof(_que));
	if(NULL == qnode){
		return ;
	}
	qnode->root = tree;
	qnode->next = NULL;
	if(0 == qctl->lenth){
		qctl->head=qctl->tail=qnode;
	}else{
		qctl->tail->next = qnode;
		qctl->tail       = qnode;
	}
	qctl->lenth += 1;
}
_tree *deq (_quectl *qctl)               //删除一个队列结点 
{
	_que * qnode = NULL ;
	_tree * tree = NULL ;
	if(NULL == qctl || 0 >= qctl->lenth){
		return NULL;
	}
	qnode = qctl->head;
	qctl->head = qnode->next;
	qctl->lenth -= 1;
	tree = qnode->root;
	free(qnode);
	return tree;
}

void que_destory(_quectl *qctl)                //破坏队列 
{
	_que * qnode = NULL;
	if(NULL == qctl){
		return ;
	}
	qnode = qctl->head;
	while(NULL != qnode){
		qctl->tail = qnode->next;
		if(PE == qnode->root->ele){
			free(qnode->root);
		}
		free(qnode);
		qnode = qctl->tail;
	}
}

void tree_create(_treectl *ctl,char *str)       //建立二叉树 
{
	_tree *root = NULL,*mtree = NULL;
	_tree *left = NULL,*right = NULL;
	int index=0       ,lenstr = 0   ;
	_quectl qctl = {NULL,NULL,0}      ;
	if(NULL == ctl || NULL == str){
		return ;
	}
	ctl->root = NULL ;
	ctl->nodes = 0	 ;
	lenstr = strlen(str);
	if(0 >= lenstr){
		return ;
	}
	mtree =(_tree *)malloc(sizeof(_tree));
	if(NULL == mtree){
		return ;
	}
	mtree->ele = str[0];
	mtree->lchd= mtree->rchd =NULL;
	ctl->root  = mtree;

	inq(&qctl,mtree);
	index += 1;
	while(index < lenstr){             
		mtree = deq(&qctl);            
		if(NULL == mtree){
			break ;
		}
		left = (_tree *)malloc(sizeof(_tree));
		right= (_tree *)malloc(sizeof(_tree));
		memset(left,0x00,sizeof(_tree));
		memset(right,0x00,sizeof(_tree));
		left->ele = str[index];
		right->ele= str[index+1];
		inq(&qctl,left);
		inq(&qctl,right);
		if(PE == mtree->ele){                    //遇到#给它的左右子树分别赋值NULL 
			left->ele = PE;
			right->ele= PE;
			free(mtree);
		}else{
			if(PE == left->ele){                 
				mtree->lchd = NULL;
			}else{
				mtree->lchd = left;
			}
			if(PE == right->ele){
				mtree->rchd = NULL;
			}else{
				mtree->rchd = right;
			}
		}
			index += 2;
	}
	que_destory(&qctl);
}



void tree_destory(_tree *tree)           //删除一棵树 
{
	if(tree){
		tree_destory(tree->lchd);
		tree_destory(tree->rchd);
		free(tree);
	}
}

void pre(_tree *tree)                    //前序遍历一棵树 
{
	if(tree)
	{
		printf("%c ",tree->ele);
		pre(tree->lchd);
		pre(tree->rchd);
	}
}
void middle(_tree *tree)                 //中序遍历一颗树 
{
	if(tree){
		middle(tree->lchd);
		printf("%c ",tree->ele);
		middle(tree->rchd);
	}
}
void post(_tree *tree)                     //后序遍历一颗树 
{
	if(tree)
	{
		post(tree->lchd);
		post(tree->rchd);
		printf("%c ",tree->ele);
	}
}


int dowork(int ac,char **av)
{
	_treectl mytree = {NULL,0};
	int height  = 0;
	_tree *node = NULL;
	if(ac <= STR){
		printf("NO input\n");
		return -1;
	}
	tree_create(&mytree,av[STR]);
	pre(mytree.root);
	printf("\n");
	middle(mytree.root);
	printf("\n");
	post(mytree.root);
	printf("\n");
	tree_destory(mytree.root);
	return 0;
}
int main(int ac,char **av)
{
	return dowork(ac,av);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/zmrlinux/p/4921428.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构关于二叉树的建立遍历以及应用二叉树进行编解码 实验要求 必做部分 1. 小明会按照前序的方式输入一棵二叉树。例如,输入$ACG##H##D##BE#I##F##的话,代表了下面这棵树: 2. 请分别按照前序、中序、后序输出这棵树。 选做部分 背景 在影视剧中,我们经常会看到二战期间情报人员使用电报哒哒哒地发送信息,发送电报所使用的编码叫做摩尔斯电码(或者叫做摩斯密码)。甚至在现代,SOS仍然是国际通用的求救信号之一,其“三短、三长、三短”同样是摩斯密码的编码方式。 摩斯密码使用若干个“点”和“划”来表示一个字母,字母和字母之间使用短暂的停顿来表示。例如,一种常见的编码方式为: 字母 摩斯密码 字母 摩斯密码 A .- E . B -... F ..-. C -.-. G --. D -.. H .... 实际上,一个摩斯密码本可以使用一棵二叉树来存储: 上图表示,从根节点start开始,遇到一个点(Dot)就访问它的左子树节点,遇到一个划(Dash)就访问它的右子树节点。例如,三个点...代表了S,三个划---代表了O。所以SOS的摩斯密码是... --- ...(中间用空格隔开,表示短暂的停顿)。再比如,爱疯手机有一种来电铃声的节奏为“哇哇哇 哇-哇- 哇哇哇”,这其实表示的是…… 现在,小明想在课上偷偷跟你传纸条,但又不想被其他同学看到内容。因此他跟你约定,每次给你传纸条时都使用摩斯密码来编写。至于密码本,当然不能使用国际通用的,他会在课前告诉你密码本的内容。然而小明发现,每次写纸条、读纸条都不是很方便,所以他想让你做个程序来自动编码/解码你们的摩斯密码。 题目要求 首先,小明输入的那棵二叉树,代表了你们在这堂课上要使用的摩斯密码本。例如,输入$ACG##H##D##BE#I##F##的话,代表了下面这棵树: 第一个字母$是什么并不重要,因为它只是代表了根节点,而根节点在我们的摩斯电码中并不代表一个字符,仅仅代表“start”。 读入密码本后,请记得按照前序、中序、后序输出这棵树。 然后,小明会输入一个数,代表接下来输入的是明文还是摩斯电码。输入0表示接下来他会输入明文,输入1表示接下来输入的是摩斯电码,输入-1程序退出。 1. 如果输入的是0,代表接下来要输入的是明文。程序接受一个字符串,根据字符串中每一个字母输出对应的摩斯电码,用空格隔开。例如如果小明输入“BED”,则程序应该输出“-空格-.空格.-”。如果遇到密码本中没有的字符,则输出“输入有误”。 2. 如果输入的是1,则表示接下来要输入摩斯电码。小明首先会输入一个数字N,代表有几个电码的输入,例如输入4代表之后会输入4个电码(即这个单词有四个字母)。随后输入空格分割的电码,例如, .. . -- -. 程序需要根据摩斯电码解读出明文单词并输出,例如上面的电码表示“CAFE”。如果遇到密码本中没有的编码,则输出“输入有误”。 输入输出样例 必做部分: 请输入二叉树: $ACG##H##D##BE#I##F## 前序遍历:$ACGHDBEIF 中序遍历:GCHAD$EIBF 后序遍历:GHCDAIEFB$ 选做部分: 请选择(0为明文,1为电码,-1退出):0 请输入明文:BED 摩斯电码为:- -. .- 请选择(0为明文,1为电码,-1退出):1 请输入电码个数:4 请输入电码:.. . -- -. 明文为:CAFE 请选择(0为明文,1为电码,-1退出):-1 // 程序结束
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值