数和二叉树——二叉树的建立及应用(遍历等)(基础篇)

二叉树:二叉树是每个结点最多有两个子树的有序树。

先来介绍一下二叉树的一些基本性质吧~

二叉树的性质:

1.非空二叉树上叶子结点数等于双分支节点数加一。

性质1 二叉树第i层上的结点数目最多为2i-1(i≥1)。
证明:用数学归纳法证明:
    
归纳基础:i=1时,有2i-1=20=1。因为第1层上只有一个根结点,所以命题成立。
   
 归纳假设:假设对所有的j(1≤j<i)命题成立,即第j层上至多有2j-1个结点,证明j=i时命题亦成立。
   
 归纳步骤:根据归纳假设,第i-1层上至多有2i-2个结点。由于二叉树的每个结点至多有两个孩子,故第i层上的结点数至多是第i-1层上的最大结点数的2倍。即j=i时,该层上至多有2×2i-2=2i-1个结点,故命题成立。
性质2
深度为k的二叉树至多有2k-1个结点(k≥1)。
证明:在具有相同深度的二叉树中,仅当每一层都含有最大结点数时,其树中结点数最多。因此利用性质1可得,深度为k的二叉树的结点数至多为:
               
20+21+…+2k-1=2k-1

等比数列求和公式:
   
故命题正确。
性质3 在任意-棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则no=n2+1。
证明:因为二叉树中所有结点的度数均不大于2,所以结点总数(记为n)应等于0度结点数、1度结点(记为n1)和2度结点数之和:
                    
n=no+n1+n2 (式子1)
    
另一方面,1度结点有一个孩子,2度结点有两个孩子,故二叉树中孩子结点总数是:
                     
nl+2n2
  树中只有根结点不是任何结点的孩子,故二叉树中的结点总数又可表示为:
                     
n=n1+2n2+1 (式子2)
  由式子1和式子2得到:
                     
no=n2+1
完全二叉树(Complete BinaryTree) 
   
若一棵二叉树至多只有最下面的两层上结点的度数可以小于2,并且最下一层上的结点都集中在该层最左边的若干位置上,则此二叉树称为完全二叉树。
 
特点:
  (1) 满二叉树是完全二叉树,完全二叉树不一定是满二叉树。
  (2)
在满二叉树的最下一层上,从最右边开始连续删去若干结点后得到的二叉树仍然是一棵完全二叉树。
  (3)
在完全二叉树中,若某个结点没有左孩子,则它一定没有右孩子,即该结点必是叶结点。

性质:对完全二叉树中编号为i的结点(n为结点数),有:

(1)若i<(n/2)(下取整),则编号为i的节点为分支节点,否则为叶子节点。

(2)若n为奇数,则每个分支节点都既有左孩子结点,也有右孩子结点。

(3)若编号为i的节点有左孩子结点,则左孩子结点的编号为2i;若编号为i的节点有右孩子结点,则左孩子结点的编号为2i+1。

(4)除树根结点外,若一个节点的编号为i,则它的双亲结点编号为(i/2)(下取整)

(5)具有n个结点的完全二叉树的深度为log2n+1。
满二叉树(FullBinaryTree) 
   
 一棵深度为k且有2k-1个结点的二又树称为满二叉树。
     满二叉树的特点:
  (1)
每一层上的结点数都达到最大值。即对给定的高度,它是具有最多结点数的二叉树。
  (2)
满二叉树中不存在度数为1的结点,每个分支结点均有两棵高度相同的子树,且树叶都在最下一层上。

基本性质讲完了,不够的欢迎补充~~

接下来说说二叉树的存储结构及其建立:

顺序存储:用一组地址连续的存储单元来存放二叉树的元素。(先确定好树中个元素的次序)

确定次序:编号:层次从上到下,每层从左到右。对于编号为i的节点,若存在左孩子,则左孩子编号为2i,若存在右孩子,则编号为2i+1;

typedef struct

{

elemtype data[maxn];//存放二叉树的节点值

int n;//元素个数

}sqbtree;

对于完全二叉树来说,顺序存储十分合适,能从分利用存储空间,但是对于一般二叉树而言,顺序存储使二叉树的插入删除等操作十分不方便。因此,我们引入链式存储:

链式存储:用一个链表来存一颗二叉树。节点定义如下:

typedef struct node

{

elemtype data;//数据元素

struct node *lchild;//指向左孩子

struct node *rchild;//指向右孩子
}BiTree;

知道存储方法以后我们就可以建立二叉树了:(此处采用链式存储)

BiTree CreateBiTree(){

char ch;

BiTree T;

scanf("%c",&ch);

if(ch==‘#‘)

T=NULL;

else{

T = (BiTree)malloc(sizeof(BiTNode));

T->data = ch;

T->lchild = CreateBiTree();//递归建树(根左右:先序建树)

T->rchild = CreateBiTree();

}

return T;//返回根节点

}

再来看看二叉树的三种遍历方式:

//先序遍历二叉树

void PreOrderTraverse(BiTree T){

if(T){

printf("%c",T->data);

PreOrderTraverse(T->lchild);

PreOrderTraverse(T->rchild);

}

}

//中序遍历

void InOrderTraverse(BiTree T){

if(T){

PreOrderTraverse(T->lchild);

printf("%c",T->data);

PreOrderTraverse(T->rchild);

}

}

//后序遍历

void PostOrderTraverse(BiTree T){

if(T){

PreOrderTraverse(T->lchild);

PreOrderTraverse(T->rchild);

printf("%c",T->data);

}

}

以上均采用递归的方式遍历,下面是非递归的方式:(利用栈)

  1 //栈的链式存储结构
  2 typedef struct LNode
  3 {
  4 BiTree data;
  5 struct LNode *next;
  6 }LNode,*LinkList;
  7
  8 //进栈
  9 Status Push(LinkList& S,BiTree T)
 10 {
 11 LinkList stack;
 12 stack=(LinkList)malloc(sizeof(LNode));   //分配空间
 13 stack->data=T;
 14 stack->next=S->next;     //进栈
 15 S->next=stack;
 16 return OK;
 17
 18 }//Push
 19 //出栈
 20 Status Pop(LinkList &S,BiTree &T)
 21 {
 22 LinkList stack;
 23 stack=S->next;    //出栈
 24 S->next=stack->next; //栈顶指向下个元素
 25 T=stack->data;
 26 return OK;
 27 }//Pop
 28 //是否为空栈
 29 Status StackEmpty(LinkList S)
 30 {
 31 if(S->next==NULL)
 32    return OK;
 33 else
 34    return ERROR;
 35 }
 36
 37 //先序非递归遍历 算法1
 38 void PreOrder1(BiTree T)
 39 {
 40 BiTree Stack[MaxSize],p;    //定义栈
 41 int top=0;
 42 p=T;
 43 while (p!=NULL||top>0)
 44 {
 45    while(p!=NULL)
 46    {
 47     cout<<p->data<<" ";    //输出结点data
 48     Stack[top]=p;     //左树进栈
 49     top++;
 50     p=p->lchild;
 51    }
 52    if(top>0)
 53    {
 54     top--;
 55     p=Stack[top];
 56     p=p->rchild;
 57    }
 58 }
 59 cout<<endl;
 60 }
 61 //先序遍历非递归 算法2
 62 void PreOrder2(BiTree b)
 63 {
 64 LinkList stack;
 65 BiTree p;
 66 p=(BiTree)malloc(sizeof(BiTree));
 67
 68
 69 stack=(LinkList)malloc(sizeof(LinkList));
 70 stack->next=NULL;
 71 Push(stack,b);      //二叉树头结点进栈
 72 while(!StackEmpty(stack))   //是否为空
 73 {
 74    Pop(stack,p);     //出栈
 75    while (p)
 76    {
 77     cout<<p->data<<" ";   //输出当前指向结点
 78     if(p->rchild)Push(stack,p->rchild); //访问右指点
 79     p=p->lchild;
 80    }
 81         }
 82 cout<<endl;
 83 }
 84 //后序非递归遍历
 85 void PostOrder(BiTree T)
 86 {
 87 BiTree stack[MaxSize],p;
 88 int top=0;
 89 p=T;
 90 do
 91 {
 92    while (p!=NULL)
 93    {
 94     stack[++top]=p;
 95     p=p->lchild;
 96    }
 97    while (top>0&&stack[top]->rchild==p)
 98    {
 99     p=stack[top--];    //栈顶结点出栈
100     cout<<p->data<<" ";   //访问p所指向的结点
101    }
102    if (top>0)
103     p=stack[top]->rchild; //开始遍历右子树
104
105 }while(top>0);
106 cout<<endl;
107 }

二叉树的基本操作已经总结完了,下面是一些补充:

  1 //计算叶子结点的个数
  2 void CountLeaf(BiTree T,int &count)
  3 {
  4
  5 if(T)
  6 {
  7    if((!T->lchild)&&(!T->rchild))
  8     count++;
  9    CountLeaf(T->lchild,count);   //左子树叶子个数
 10    CountLeaf(T->rchild,count);   //右子树叶子个数
 11 }
 12 }//CountLeaf
 13 //计算双结点个数
 14 void CountParent(BiTree T,int &count)
 15 {
 16 if(T)
 17 {
 18 if(T->lchild&&T->rchild)
 19    count++;
 20 CountParent(T->lchild,count); //左子树双结点个数
 21 CountParent(T->rchild,count); //右子树双结点个数
 22 }
 23 }
 24 //计算二叉树结点个数
 25 void Count(BiTree T,int &count)
 26 {
 27 if(T)
 28 {
 29    Count(T->lchild,count);
 30    Count(T->rchild,count);
 31    count++;      //结点个数
 32 }
 33
 34 }
 35 //单结点个数
 36 void CountChild(BiTree T,int &count)
 37 {
 38 if(T)
 39 {
 40    if((T->lchild&&(!T->rchild))||(T->rchild&&(!T->lchild)))
 41     count++;
 42    CountChild(T->lchild,count);   //左子树单结点个数
 43    CountChild(T->rchild,count);   //右子树单结点个数
 44 }
 45 }
 46 //计算树的高度
 47 int Depth(BiTree T)
 48 { int depthval,depthLeft,depthRight;
 49 if(!T) depthval=0;
 50 else
 51 {depthLeft=Depth(T->lchild);     //左子树高度
 52 depthRight=Depth(T->rchild);     //右子树高度
 53 depthval=1+(depthLeft>depthRight ?depthLeft:depthRight);   //取高度最高
 54 }
 55 return depthval;        //返回
 56 }
 57 //计算任意结点所在的层次
 58 int NodeLevel(BiTree T,TElemType &p,int &count)
 59 {
 60 if(T==NULL)
 61    return 0;
 62 if(T->data==p)
 63    return 1;
 64 if(NodeLevel(T->lchild,p,count)||(NodeLevel(T->rchild,p,count)))
 65 {
 66    count++;
 67    return 1;
 68 }
 69 // return 0;
 70
 71 }
 72 //交换二叉树左右子树
 73 void Exchange(BiTree &T)
 74 {
 75
 76 BiTree temp;
 77 if (T == NULL)
 78    return;
 79 Exchange(T ->lchild);   //交换左子树
 80 Exchange(T ->rchild);   //交换右子树
 81 temp = NULL;
 82 temp = T ->lchild;    //交换
 83 T->lchild=T->rchild;
 84 T->rchild=temp;
 85
 86 }
 87 //判断两树是否相似
 88 int LikeBiTree(BiTree T1,BiTree T2)
 89 {
 90 int like1,like2;
 91    if(T1==NULL&&T2==NULL)
 92     return 1;
 93    else if(T1==NULL||T2==NULL)
 94     return 0;
 95    else
 96    {
 97     like1=LikeBiTree(T1->lchild,T2->lchild);
 98     like2=LikeBiTree(T1->rchild,T2->rchild);
 99     return(like1&&like2);
100    }
101
102 }//LikeBiTree

层次遍历二叉树(队列实现)

 1 /*
 2 二叉树的层次遍历
 3 input:
 4 2
 5 10 5 4 -1 -1 -1 20 19 -1 -1 40 -1 -1
 6 30 10 8 20 -1 -1 -1 -1 50 40 -1 45 -1 -1 -1
 7 output:
 8 10 5 20 4 19 40
 9 30 10 50 8 40 20 45
10 */
11 #include<iostream>
12 #include<queue>
13 using namespace std;
14 struct BTreeNode{
15     //二叉树
16     int data;
17     BTreeNode *lchild;
18     BTreeNode *rchild;
19 };
20 void LayerOrder(BTreeNode *t){
21     //利用队列实现层次遍历,每次访问根结点,然后一次放入左结点和右结点(如果有的话)。
22     if(t == NULL)return ;
23     queue<BTreeNode*> q;
24     BTreeNode *temp;
25     q.push(t);
26     while(!q.empty()){
27         temp = q.front();
28         q.pop();
29         cout<<temp->data<<‘ ‘;
30         if(temp->lchild != NULL)q.push(temp->lchild);
31         if(temp->rchild != NULL)q.push(temp->rchild);
32     }
33 }
34 void Create(BTreeNode *&t){
35     //(测试用)以先序遍历构建二叉树
36     int x;
37     cin>>x;
38     if(x == -1)
39         t = NULL;
40     else
41     {
42         t = new BTreeNode;
43         t->data = x;
44         Create(t->lchild);
45         Create(t->rchild);
46     }
47 }
48 int main(){
49     BTreeNode *root = NULL;
50     int t;
51     cin>>t;
52     while(t--)
53     {
54         Create(root);
55         LayerOrder(root);
56         cout<<endl;
57     }
58     return 0;
59 }

基础篇讲完啦~~~快下课了(上机课已经无聊到写博客了==造福人类吖*。*)

时间: 2024-11-13 00:07:48

数和二叉树——二叉树的建立及应用(遍历等)(基础篇)的相关文章

树(二叉树)的建立和遍历算法(一)(前序,中序,后序)

最近学习树的概念,有关二叉树的实现算法记录下来... 不过学习之前要了解的预备知识:树的概念:二叉树的存储结构:二叉树的遍历方法.. 二叉树的存储结构主要了解二叉链表结构,也就是一个数据域,两个指针域,(分别为指向左右孩子的指针),从下面程序1,二叉树的存储结构可以看出. 二叉树的遍历方法:主要有前序遍历,中序遍历,后序遍历,层序遍历.(层序遍历下一篇再讲,本篇主要讲的递归法) 如这样一个二叉树: 它的前序遍历顺序为:ABDGHCEIF(规则是先是根结点,再前序遍历左子树,再前序遍历右子树) 它

二叉树的建立及递归遍历

huangjing 二叉树的的建立方式为前序  二叉树有三种遍历  前序遍历(NLR)  中序遍历(LNR)  后续遍历(LRN) 非递归的算法明天补上 代码为: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<map> #include<vector> #include

二叉树的前序建立,前中后序遍历的非递归算法

二叉树的前序建立递归算法以及前中后序遍历的递归算法已经是人尽皆知了,递归算法也确实为代码的编写带来了很大的方便.然而,有时我们也确实需要它们的非递归算法.将递归算法转化为非递归算法可以帮助我们深入了解函数的调用与栈的原理.这里总结一下二叉树的这些重要的非递归算法. 一.前序建树 前序建树的基本思路是,接收用户输入的一组字符串,其中'#'代表空树,其他代表树结点的数据域值.例如,要建立如下一棵树 需要输入"AB#D##C##". 而非递归的思路是,1.设一个标志位来判断当前创建的结点是左

二叉树总结—建树和4种遍历方式(递归&amp;&amp;非递归)

今天总结一下二叉树,要考离散了,求不挂!二叉树最重要的就是 建立.4种遍历方式,简单应用,如何判断两颗二叉树是否相似 二叉树分为 :1.完全二叉树  2.满二叉树 结构性质: 1).满二叉树 高度为h ,节点数则为 2^h - 1,且叶子节点全在最下层,且叶子节点数为2^(n-1)个{n代表二叉树层数,也叫深度} 2).n个节点的 完全二叉树 深度为 int(log2n)(以2为底n的对数)+ 1: 3).非空二叉树 叶子节点个数==双分支节点数+1 4).非空二叉树 某节点编号 n  若有左孩

二叉树 二叉树的性质 存储结构 遍历二叉树 C实现二叉树的创建和遍历 线索二叉树

定义 二叉树(binary tree)是n(n>=0)个结点的有限集合,该集合为空集合称为空二叉树,或者有一个根结点和两棵互不相交的,分别称为树根结点的左孩子树和右孩子树组成. 二叉树的特点 每个结点最多有两棵子树,所以二叉树总没有度大于2的结点 左子树和右子树是有顺序的,次数不能任意颠倒 即使树中某结点只有一棵子树,也要区分是左子树还是右子树 特殊的二叉树 1. 斜树 所有的结点都只有左子树的二叉树称为左斜树; 所有的结点都只有右子树的二叉树称为右斜树; 这两者统称为斜树 2. 满二叉树 在一

二叉树的创建和四种遍历(前序、先序、后序、层次、结点的层数、深度、叶子数等)—java描述

二叉树的创建和四种遍历(前序.先序.后序.层次.结点的层数.深度.叶子数等)—java描述 package javab; //树的结点类 public class TreeNode { String data; TreeNode leftChild,rightChild,next; public TreeNode(String data){ this.data=data; } public TreeNode(String data,TreeNode left,TreeNode right){ l

javascript实现数据结构: 树和二叉树,二叉树的遍历和基本操作

树型结构是一类非常重要的非线性结构.直观地,树型结构是以分支关系定义的层次结构. 树在计算机领域中也有着广泛的应用,例如在编译程序中,用树来表示源程序的语法结构:在数据库系统中,可用树来组织信息:在分析算法的行为时,可用树来描述其执行过程等等. 下面讲解的内容完整代码在这:https://github.com/LukeLin/data-structure-with-js/blob/master/Binary%20tree/BinaryTree.js 首先看看树的一些概念: 1.树(Tree)是n

二叉树的递归和非递归遍历

// 本次练习的是  二叉树的  递归和非递归  遍历   以及二叉树的  节点数  高度  叶子节点数   和查找功能  //如果要是变量在函数栈回归时不回归原值,则可以用引用// #define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<stack>#include<queue>using namespace std; template<class T>struct BinaryTreeNod

笔试算法题(36):寻找一棵二叉树中最远节点的距离 &amp; 根据二叉树的前序和后序遍历重建二叉树

出题:求二叉树中距离最远的两个节点之间的距离,此处的距离定义为节点之间相隔的边数: 分析: 最远距离maxDis可能并不经过树的root节点,而树中的每一个节点都可能成为最远距离经过的子树的根节点:所以计算出以每个节点为根节点的子树的最 远距离,最后取他们的最大值就是整棵树的最远距离: 如果递归层次过多造成系统栈溢出,则可以使用stack堆栈结构存储递归节点,从而使用循环实现 解题: 1 struct Node { 2 int value; 3 Node *left; 4 Node *right