数据结构二叉树的基本操作~~~~
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构二叉树的基本操作~~~~相关的知识,希望对你有一定的参考价值。
RT
类似的建立二叉树~~~
1.以二叉链表表示二叉树,建立一棵二叉树;
2.输出二叉树的前序遍历结果;
3.输出二叉树的中序遍历结果;
4.输出二叉树的后序遍历结果;
5.统计二叉树的叶结点个数;
6.统计二叉树的结点个数;
7.计算二叉树的深度。
8.交换二叉树每个结点的左孩子和右孩子;
#include <malloc.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#define OK 1
#define NULL 0
#define FALSE 0
typedef struct BiTNode //定义链式二叉树结构体
char data;
struct BiTNode *lchild,*rchild;
BiTNode,*BiTree;
BiTree T;
char ch;
int flag=0;
int createBiTree(BiTree &T)
//按先序输入二叉树中结点的值(一个字符),空格表示空树
ch=getchar();
if(ch==' ')T=NULL; //表示空树
else if(ch==10)flag=1; //结点信息输入错误则返回0
else
T=(BiTNode*)malloc(sizeof(BiTree));
if(!T)exit(1);//空间分配不成功则退出
T->data=ch; //生成根结点
createBiTree(T->lchild); //生成左子树
createBiTree(T->rchild); //生成右子树
//else
return OK;
//createBiTree
int PreOrderTraverse(BiTree T) //先序遍历二叉树的递归算法
if(T)
printf("%c",T->data); //访问根结点
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
//if
return OK;
int InOrderTraverse(BiTree T) //中序
if(T)
InOrderTraverse(T->lchild);
printf("%c",T->data); //访问根结点
InOrderTraverse(T->rchild);
//if
return OK;
int PostOrderTraverse(BiTree T) // 后序
if(T)
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data); //访问根结点
return OK;
int NodeCount(BiTree T) //
if(T==NULL) return 0;// 如果是空树,则结点个数为0
else return 1+NodeCount(T->lchild)+NodeCount(T->rchild);
//否则结点个数为1+左子树的结点个数+右子树的结点个数
int LeafNodeCount(BiTree T )
if(!T)return 0; //如果是空树,则叶子个数为0;
else if(LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild)==0)return 1;//如果是叶子结点,则叶子结点个数为1
else return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);
//否则叶结点个数为左子树的叶结点个数+右子树的叶结点个数
int Depth(BiTree T)//计算二叉树的深度
int m,n;
if(T==NULL )return 0;//如果是空树,则深度为0
else
m=Depth(T->lchild);//计算左子树的深度记为m
n=Depth(T->rchild);//计算右左子树的深度记为n
if(m>n) return(m+1);//二叉树的深度为m 与n的较大者加1
else return (n+1);
void Exchange1(BiTree T)
BiTree temp;
if(T)
Exchange1(T->lchild);
Exchange1(T->rchild);
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
void main()
int no,out=1;
char choose;
//*****************************主界面**********************************
while(out)
system("cls");
printf("\n这是实验2的程序,请按照说明使用:\n");
printf("1.以二叉链表表示二叉树,建立一棵二叉树,请输入1");
printf("\n2.输出二叉树的前序遍历结果,请输入2");
printf("\n3.输出二叉树的中序遍历结果,请输入3");
printf("\n4.输出二叉树的后序遍历结果请输入4");
printf("\n5.统计二叉树的结点个数,请输入5");
printf("\n6.统计二叉树的叶结点个数,请输入6");
printf("\n7.计算二叉树的深度,请输入7");
printf("\n8. 交换二叉树的左右孩子,请输入8");
printf("\n9.退出,请输入其他\n");
//********************处理输入的选项************************************
choose=getch();
switch(choose)
case '1':
system("cls");
printf("\n请输入二叉链表各结点信息建立二叉树,空树用空格表示:\n");
if(createBiTree(T)==0||flag==1) //结点输入错误!
printf("输入错误,请重新输入结点信息!\n");
getch();break;
else
printf("输入完毕!");//成功建立二叉链表
getch();break;
case '2':
printf("\n先序遍历的结果是:");
PreOrderTraverse(T);
getch();break;
case '3':
printf("\n中序遍历的结果是:");
InOrderTraverse(T);
getch();break;
case '4':
printf("\n后序遍历的结果是:");
PostOrderTraverse(T);
getch();break;
case '5':
no=NodeCount(T);
printf("\n总结点个数为:%d\n",no);
getch();break;
case '6':
printf("\n叶子结点的个数为:%d\n",LeafNodeCount(T));
getch();break;
case '7':
printf("\n二叉树深度为:%d\n",Depth(T));
getch();break;
case '8':
printf("\n交换后的结果为:");
Exchange1(T);
PostOrderTraverse(T);
getch();break;
default :
printf("\n你输入的是:其他\n");
getch();
out=0;
//end switch
//end of while
system("cls");
printf("\n\n\t\t欢迎使用,再见!");
碉堡了! 参考技术A 二叉树的基本操作 C语言实现/*程序实现内容
1.采用二叉树链表作为存储结构,建立二叉树;
2.对二叉树分别按先、中、后序以及按层次遍历,输出相应的访问序列;
3.计算二叉树的深度,统计所有叶子结点总数及树中包含的结点总数。*/
#include"stdio.h"
#include"string.h"
#include"malloc.h"
#define Max 20 //结点的最大个数
typedef struct node
char data;
struct node *lchild,*rchild;
BinTNode; //自定义二叉树的结点类型
typedef BinTNode *BinTree; //定义二叉树的指针
int NodeNum,leaf; //NodeNum为结点数,leaf为叶子数
//基于先序遍历算法创建二叉树
//要求输入先序序列,其中加入虚结点“#”以示空指针的位置
BinTree CreatBinTree(void)
BinTree T;
char ch;
if((ch=getchar())=='#')
return(NULL); //读入#,返回空指针
else
T=(BinTNode *)malloc(sizeof(BinTNode));//生成结点
T->data=ch;
T->lchild=CreatBinTree(); //构造左子树
T->rchild=CreatBinTree(); //构造右子树
return(T);
//DLR 先序遍历
void Preorder(BinTree T)
if(T)
printf("%c",T->data); //访问结点
Preorder(T->lchild); //先序遍历左子树
Preorder(T->rchild); //先序遍历右子树
//LDR 中序遍历
void Inorder(BinTree T)
if(T)
Inorder(T->lchild); //中序遍历左子树
printf("%c",T->data); //访问结点
Inorder(T->rchild); //中序遍历右子树
//LRD 后序遍历
void Postorder(BinTree T)
if(T)
Postorder(T->lchild); //后序遍历左子树
Postorder(T->rchild); //后序遍历右子树
printf("%c",T->data); //访问结点
//采用后序遍历求二叉树的深度、结点数及叶子数的递归算法
int TreeDepth(BinTree T)
int hl,hr,max;
if(T)
hl=TreeDepth(T->lchild); //求左深度
hr=TreeDepth(T->rchild); //求右深度
max=hl>hr? hl:hr; //取左右深度的最大值
NodeNum=NodeNum+1; //求结点数
if(hl==0&&hr==0) leaf=leaf+1; //若左右深度为0,即为叶子。
return(max+1);
else return(0);
//利用“先进先出”(FIFO)队列,按层次遍历二叉树
void Levelorder(BinTree T)
int front=0,rear=1;
BinTNode *cq[Max],*p; //定义结点的指针数组cq
cq[1]=T; //根入队
while(front!=rear)
front=(front+1)%NodeNum;
p=cq[front]; //出队
printf("%c",p->data); //出队,输出结点的值
if(p->lchild!=NULL)
rear=(rear+1)%NodeNum;
cq[rear]=p->lchild; //左子树入队
if(p->rchild!=NULL)
rear=(rear+1)%NodeNum;
cq[rear]=p->rchild; //右子树入队
//主函数
main()
BinTree root;
int i,depth;
printf("\n");
printf("Creat Bin_Tree; Input preorder:"); //输入完全二叉树的先序序列,
// 用#代表虚结点,如ABD###CE##F##
root=CreatBinTree(); //创建二叉树,返回根结点
do //从菜单中选择遍历方式,输入序号。
printf("\t********** select ************\n");
printf("\t1: Preorder Traversal\n");
printf("\t2: Iorder Traversal\n");
printf("\t3: Postorder traversal\n");
printf("\t4: PostTreeDepth,Node number,Leaf number\n");
printf("\t5: Level Depth\n"); //按层次遍历之前,先选择4,求出该树的结点数。
printf("\t0: Exit\n");
printf("\t*******************************\n");
scanf("%d",&i); //输入菜单序号(0-5)
switch (i)
case 1: printf("Print Bin_tree Preorder: ");
Preorder(root); //先序遍历
break;
case 2: printf("Print Bin_Tree Inorder: ");
Inorder(root); //中序遍历
break;
case 3: printf("Print Bin_Tree Postorder: ");
Postorder(root); //后序遍历
break;
case 4: depth=TreeDepth(root); //求树的深度及叶子数
printf("BinTree Depth=%d BinTree Node number=%d",depth,NodeNum);
printf(" BinTree Leaf number=%d",leaf);
break;
case 5: printf("LevePrint Bin_Tree: ");
Levelorder(root); //按层次遍历
break;
default: exit (1);
printf("\n");
while(i!=0);本回答被提问者采纳
树与二叉树数据结构详解
一、树的基本概念
1.树的知识框架
1.树的定义
树是n(n>=0)个结点的有限集。当n = 0时,称为空树。在任意一棵非空树中应满足:
- 有且仅有一个特定的称为根的结点。
- 当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每个集合本身又是一棵树,并且称为根的子树。
显然,树的定义是递归的,即在树的定义中又用到了自身,树是一种递归的数据结构。树作为一种逻辑结构,同时也是一种分层结构,具有以下两个特点:
- 树的根结点没有前驱,除根结点外的所有结点有且只有一个前驱。
- 树中所有结点可以有零个或多个后继。
因此n个结点的树中有n-1条边。
3.树的基本术语
结合图示来说明一下树的一些基本术语和概念。
- 考虑结点K。根A到结点K的唯一路径上的任意结点,称为结点K的祖先。如结点B是结点K的祖先,而结点K是结点B的子孙。路径上最接近结点K的结点E称为K的双亲,而K为结点E的孩子。根A是树中唯一没有双亲的结点。有相同双亲的结点称为兄弟,如结点K和结点L有相同的双亲E,即K和L为兄弟。
- 树中其中某个结点的孩子个数称为该结点的度,树中结点的最大度数称为树的度。如结点B的度为2,结点D的度为3(此结点度最大),树的度为3。
- 度大于0的结点称为分支结点(又称非终端结点);度为0(没有孩子结点)的结点称为叶子结点(又称终端结点)。在分支结点中,每个结点的分支数就是该结点的度。
- 结点的深度、高度和层次。
结点的层次从树根开始定义,根结点为第1层,它的子结点为第2层,以此类推。双亲在同一层的结点互为堂兄弟,图中结点G与E,F,H,I,J互为堂兄弟。
结点的深度是从根结点开始自顶向下逐层累加的。它可以是某一层,例如结点F所在的深度为3,而L结点所在的深度为4。
结点的高度是从叶结点开始自底向上逐层累加的。高度只讲的是树的高度,树的高度为4。
树的高度(或深度)是树中结点的最大层数。图中树的高度为4。 - 有序树和无序树。**树中结点的各子树从左到右是有次序的,不能互换,称该树为有序树,否则称为无序树。**假设图为有序树,若将子结点位置互换,则变成一棵不同的树。
- 路径和路径长度。树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的,而路径长度是路径上所经过的边的个数。
注意:由于树中的分支是有向的,即从双亲指向孩子,所以树中的路径是从上向下的,同一双亲的两个孩子之间不存在路径。 - 森林。森林是m (m≥0)棵互不相交的树的集合。森林的概念与树的概念十分相近,因为只要把树的根结点删去就成了森林。反之,只要给m棵独立的树加上一个结点,并把这m棵树作为该结点的子树,则森林就变成了树。一棵树也可以称作一个森林。
4.树的性质
注意其中两个性质:
1、
其中这两个性质是可以互相转化的,只要记住其中一个性质就行。
2、
这个性质可以推为:
1.已经父亲结点的下标为i,则其左孩子的结点为2i+1,右孩子的结点为2i+2。
2.已知孩子结点n,推父亲节点:(n-1)/2 。
面试题:
比如:假设一棵完全二叉树中总共有1000个节点,则该二叉树中多少个叶子节点,多少个非叶子节点,多少个节点只有左孩子,多少个节点只有右孩子。
答:因为该二叉树是一棵完全二叉树,所以不可能有结点是只有右孩子的,因此最后一个空为0。
再求出该二叉树一共有多少层,因为有1000个结点,又由log2的(n+1)向上取整得深度为10,但是第十层还没放满(放满的结点数为2的10次方-1)。我们还可以求出10层前的结点一共有多少个,由2的9次方-1得511,所以第十层放的是1000-511=489个结点。
因此第十层的489个结点都为叶子结点,但是不要忘了第十层是未放满的,因此推出第九层中也是有叶子结点的。将第十层的叶子结点除2,得第9层的非叶子结点为:489/2=244.5,说明有第九层非叶子结点中有一个结点是只有左节点的。第九层结点个数:2的(9-1)次方=256个。因此非叶子结点有245个。求得第九层的叶子结点为256-245=11个。所以一共加起来的叶子结点有11+489=500个。
又因为二叉树的结点数是由叶子结点和非叶子结点组成的,所以非叶子结点有1000-500==500个,叶子结点有500个,只有左孩子的只有1个,没有只有右孩子的结点。
5.树的存储结构
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,具体如下:
// 孩子表示法
class Node
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
// 孩子双亲表示法
class Node
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
其实二叉树如何表示,主要是看创建的TreeNode结点类是如何设置来存储二叉树中的结点的。不过大多数情况下都是采取孩子表示法来构建二叉树。
二、二叉树的操作
1.二叉树的遍历
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题(比如:打印节点内容、节点内容加1)。 遍历是二叉树上最重要的操作之一,是二叉树上进行其它运算之基础。
在遍历二叉树时,如果没有进行某种约定,每个人都按照自己的方式遍历,得出的结果就比较混乱,如果按照某种规则进行约定,则每个人对于同一棵树的遍历结果肯定是相同的。如果N代表根节点,L代表根节点的左子树,R代表根节点的右子树,则根据遍历根节点的先后次序有以下遍历方式:
二叉树的遍历分为:
1.NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点—>根的左子树—>根的右子树。
2.LNR:中序遍历(Inorder Traversal)——根的左子树—>根节点—>根的右子树。
3.LRN:后序遍历(Postorder Traversal)——根的左子树—>根的右子树—>根节点。
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。
2.二叉树的基本操作
import java.util.*;
class TreeNode
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val)
this.val = val;
public class BinaryTree
public TreeNode creatTree()
TreeNode A = new TreeNode('A');
TreeNode B = new TreeNode('B');
TreeNode C = new TreeNode('C');
TreeNode D = new TreeNode('D');
TreeNode E = new TreeNode('E');
TreeNode F = new TreeNode('F');
TreeNode G = new TreeNode('G');
TreeNode H = new TreeNode('H');
A.left = B;
B.left = D;
B.right = E;
E.right = H;
A.right = C;
C.left = F;
C.right = G;
return A;
// 前序遍历
void preOrderTraversal(TreeNode root)
if (root == null)
return;
System.out.print(root.val + " ");
preOrderTraversal(root.left);
preOrderTraversal(root.right);
// 中序遍历
void inOrderTraversal(TreeNode root)
if (root == null)
return;
inOrderTraversal(root.left);
System.out.print(root.val + " ");
inOrderTraversal(root.right);
// 后序遍历
void postOrderTraversal(TreeNode root)
if (root == null)
return;
postOrderTraversal(root.left);
postOrderTraversal(root.right);
System.out.print(root.val + " ");
// 遍历思路-求结点个数
static int size = 0;
void getSize1(TreeNode root)
if (root == null)
return;
getSize1(root.left);
getSize1(root.right);
size++;
// 子问题思路-求结点个数
int getSize2(TreeNode root)
if (root == null)
return 0;
return getSize2(root.left) + getSize2(root.right) + 1;
// 遍历思路-求叶子结点个数
static int leafSize = 0;
void getLeafSize1(TreeNode root)
if (root == null)
return;
if (root.left == null && root.right == null)
leafSize++;
getLeafSize1(root.left);
getLeafSize1(root.right);
// 子问题思路-求叶子结点个数
int getLeafSize2(TreeNode root)
if (root == null)
return 0;
if (root.left == null && root.right == null)
return 1;
return getLeafSize2(root.left) + getLeafSize2(root.right);
// 子问题思路-求第 k 层结点个数
int getKLevelSize(TreeNode root, int k)
if (root == null)
return 0;
if (k == 1)
return 1;
return getKLevelSize(root.left, k - 1) + getKLevelSize(root.right, k - 1);
// 获取二叉树的高度
int getHeight(TreeNode root)
if (root == null)
return 0;
int leftNode = getHeight(root.left);
int rightNode = getHeight(root.right);
return Math.max(rightNode, leftNode) + 1;
// 查找 val 所在结点,没有找到返回 null
// 按照 根 -> 左子树 -> 右子树的顺序进行查找
// 一旦找到,立即返回,不需要继续在其他位置查找
TreeNode find(TreeNode root, char val)
if (root == null)
return null;
if (root.val == val)
return root;
TreeNode ret = find(root.left, val);
if (ret != null)
return ret;
ret = find(root.right, val);
if (ret != null)
return ret;
return null;
// 层序遍历
void levelOrderTraversal(TreeNode root)
if (root == null)
return;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty())
TreeNode top = queue.poll();
System.out.print(top.val + " ");
if (top.left != null)
queue.offer(top.left);
if (top.right != null)
queue.offer(top.right);
System.out.println();
//层序遍历
public List<List<Character>> levelOrder(TreeNode root)
List<List<Character>> list = new ArrayList<>();
if (root == null)
return list;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty())
List<Character> list1 = new ArrayList<>();
int size = queue.size();
while (size != 0)
TreeNode top = queue.poll();
list1.add(top.val);
if (top.left != null)
queue.add(top.left);
if (top.right != null)
queue.add(top.right);
size--;
list.add(list1);
return list;
// 判断一棵树是不是完全二叉树
boolean isCompleteTree(TreeNode root)
if (root == null)
return true;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty())
TreeNode top = queue.poll();
if (top != null)
queue.offer(top.left);
queue.offer(top.right);
else
break;
while(!queue.isEmpty())
TreeNode cur = queue.peek();
if(cur==null)
queue.poll();
else
return false;
return true;
//求二叉树的左视图
public void leftScenery(TreeNode root)
if(root==null)
return ;
List<List<TreeNode>> list = new LinkedList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty())
List<TreeNode> list1 = new LinkedList<>();
int size = queue.size();
while(size!=0)
TreeNode top = queue.poll();
list1.add(top);
if(top.left!=null)
queue.offer(top.left);
if(top.right!=null)
queue.offer(top.right);
size--;
list.add(list1);
for (List<TreeNode> e:list)
for (TreeNode p: e)
System.out.print(p.val+" ");
break;
//二叉树的非递归先序遍历
public void preOrderTraversalNot(TreeNode root)
if(root==null)
return;
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<>();
while(cur!=null||!stack.empty())
while(cur!=null)
stack.push(cur);
System.out.print(cur.val+" ");
cur=cur.left;
TreeNode top = stack.pop();
cur=top.right;
// 中序遍历
public void inOrderTraversalNot(TreeNode root)
if(root==null)
return;
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<>();
while(cur!=null||!stack.empty())
while(cur!=null)
stack.push(cur);
cur=cur.left;
TreeNode top = stack.pop();
System.out.print(top.val+" ");
cur=top.right;
// 后序遍历非递归
public void postOrderTraversalNot(TreeNode root)
if(root==null)
return;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode pre = null;
while(cur!=null||!stack.empty())
while(cur!=null)
stack.push(cur);
cur=cur.left;
cur=stack.peek();
if(cur.right==null||cur.right==pre)
TreeNode top = stack.pop();
System.out.print(top.val+" ");
pre=以上是关于数据结构二叉树的基本操作~~~~的主要内容,如果未能解决你的问题,请参考以下文章