Ⅰ 二叉树按照层序遍历的方法是什么
二叉树按照层序遍历,依次编号,按照编号的顺序,存储在连续存储单元的方式就是二叉树的顺序存储。
Ⅱ 二叉树如何遍历
二叉树的遍历,通常用递归的方法来描述。
先根遍历或者先序遍历:首先访问根结点,然后访问左子树,最后访问右子树。
中根便利或者中序遍历:先访问左子树,然后访问根节点,最后访问右子树。
后根遍历或者先后序遍历:首先访问左子树,然后访问根节点,最后访问右子树。
按层次遍历:从最上面一层,也就是根节点所在的一层开始,从上往下从左到右,访问二叉树中的每一个节点。
Ⅲ 二叉树的层次遍历
二叉树具有以下重要性质: 性质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 满二叉树和完全二叉树是二叉树的两种特殊情形。 1、满二叉树(FullBinaryTree) 一棵深度为k且有2k-1个结点的二又树称为满二叉树。 满二叉树的特点: (1) 每一层上的结点数都达到最大值。即对给定的高度,它是具有最多结点数的二叉树。 (2) 满二叉树中不存在度数为1的结点,每个分支结点均有两棵高度相同的子树,且树叶都在最下一层上。 【例】图(a)是一个深度为4的满二叉树。 2、完全二叉树(Complete BinaryTree) 若一棵二叉树至多只有最下面的两层上结点的度数可以小于2,并且最下一层上的结点都集中在该层最左边的若干位置上,则此二叉树称为完全二叉树。 特点: (1) 满二叉树是完全二叉树,完全二叉树不一定是满二叉树。 (2) 在满二叉树的最下一层上,从最右边开始连续删去若干结点后得到的二叉树仍然是一棵完全二叉树。 (3) 在完全二叉树中,若某个结点没有左孩子,则它一定没有右孩子,即该结点必是叶结点。 【例】如图(c)中,结点F没有左孩子而有右孩子L,故它不是一棵完全二叉树。 【例】图(b)是一棵完全二叉树。 性质4 具有n个结点的完全二叉树的深度为 证明:设所求完全二叉树的深度为k。由完全二叉树定义可得: 深度为k得完全二叉树的前k-1层是深度为k-1的满二叉树,一共有2k-1-1个结点。 由于完全二叉树深度为k,故第k层上还有若干个结点,因此该完全二叉树的结点个数: n>2k-1-1。 另一方面,由性质2可得: n≤2k-1, 即:2k-1-l<n≤2k-1 由此可推出:2k-1≤n<2k,取对数后有: k-1≤lgn<k 又因k-1和k是相邻的两个整数,故有 , 由此即得: 注意: 的证明【参见参考书目】
Ⅳ 二叉树的层次遍历
设计一个算法层序遍历二叉树(同一层从左到右访问)。思想:用一个队列保存被访问的当前节点的左右孩子以实现层序遍历。
void HierarchyBiTree(BiTree Root){
LinkQueue *Q; // 保存当前节点的左右孩子的队列
InitQueue(Q); // 初始化队列
if (Root == NULL) return ; //树为空则返回
BiNode *p = Root; // 临时保存树根Root到指针p中
Visit(p->data); // 访问根节点
if (p->lchild) EnQueue(Q, p->lchild); // 若存在左孩子,左孩子进队列
if (p->rchild) EnQueue(Q, p->rchild); // 若存在右孩子,右孩子进队列
while (!QueueEmpty(Q)) // 若队列不空,则层序遍历 { DeQueue(Q, p); // 出队列
Visit(p->data);// 访问当前节点
if (p->lchild) EnQueue(Q, p->lchild); // 若存在左孩子,左孩子进队列
if (p->rchild) EnQueue(Q, p->rchild); // 若存在右孩子,右孩子进队列
}
DestroyQueue(Q); // 释放队列空间
return ;
这个已经很详细了!你一定可以看懂的!加油啊!
Ⅳ 用java怎么构造一个二叉树呢
二叉树的相关操作,包括创建,中序、先序、后序(递归和非递归),其中重点的是java在先序创建二叉树和后序非递归遍历的的实现。
package com.algorithm.tree;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
public class Tree<T> {
private Node<T> root;
public Tree() {
}
public Tree(Node<T> root) {
this.root = root;
}
//创建二叉树
public void buildTree() {
Scanner scn = null;
try {
scn = new Scanner(new File("input.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
root = createTree(root,scn);
}
//先序遍历创建二叉树
private Node<T> createTree(Node<T> node,Scanner scn) {
String temp = scn.next();
if (temp.trim().equals("#")) {
return null;
} else {
node = new Node<T>((T)temp);
node.setLeft(createTree(node.getLeft(), scn));
node.setRight(createTree(node.getRight(), scn));
return node;
}
}
//中序遍历(递归)
public void inOrderTraverse() {
inOrderTraverse(root);
}
public void inOrderTraverse(Node<T> node) {
if (node != null) {
inOrderTraverse(node.getLeft());
System.out.println(node.getValue());
inOrderTraverse(node.getRight());
}
}
//中序遍历(非递归)
public void nrInOrderTraverse() {
Stack<Node<T>> stack = new Stack<Node<T>>();
Node<T> node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
System.out.println(node.getValue());
node = node.getRight();
}
}
//先序遍历(递归)
public void preOrderTraverse() {
preOrderTraverse(root);
}
public void preOrderTraverse(Node<T> node) {
if (node != null) {
System.out.println(node.getValue());
preOrderTraverse(node.getLeft());
preOrderTraverse(node.getRight());
}
}
//先序遍历(非递归)
public void nrPreOrderTraverse() {
Stack<Node<T>> stack = new Stack<Node<T>>();
Node<T> node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
System.out.println(node.getValue());
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
node = node.getRight();
}
}
//后序遍历(递归)
public void postOrderTraverse() {
postOrderTraverse(root);
}
public void postOrderTraverse(Node<T> node) {
if (node != null) {
postOrderTraverse(node.getLeft());
postOrderTraverse(node.getRight());
System.out.println(node.getValue());
}
}
//后续遍历(非递归)
public void nrPostOrderTraverse() {
Stack<Node<T>> stack = new Stack<Node<T>>();
Node<T> node = root;
Node<T> preNode = null;//表示最近一次访问的节点
while (node != null || !stack.isEmpty()) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
node = stack.peek();
if (node.getRight() == null || node.getRight() == preNode) {
System.out.println(node.getValue());
node = stack.pop();
preNode = node;
node = null;
} else {
node = node.getRight();
}
}
}
//按层次遍历
public void levelTraverse() {
levelTraverse(root);
}
public void levelTraverse(Node<T> node) {
Queue<Node<T>> queue = new LinkedBlockingQueue<Node<T>>();
queue.add(node);
while (!queue.isEmpty()) {
Node<T> temp = queue.poll();
if (temp != null) {
System.out.println(temp.getValue());
queue.add(temp.getLeft());
queue.add(temp.getRight());
}
}
}
}
//树的节点
class Node<T> {
private Node<T> left;
private Node<T> right;
private T value;
public Node() {
}
public Node(Node<T> left,Node<T> right,T value) {
this.left = left;
this.right = right;
this.value = value;
}
public Node(T value) {
this(null,null,value);
}
public Node<T> getLeft() {
return left;
}
public void setLeft(Node<T> left) {
this.left = left;
}
public Node<T> getRight() {
return right;
}
public void setRight(Node<T> right) {
this.right = right;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
测试代码:
package com.algorithm.tree;
public class TreeTest {
/**
* @param args
*/
public static void main(String[] args) {
Tree<Integer> tree = new Tree<Integer>();
tree.buildTree();
System.out.println("中序遍历");
tree.inOrderTraverse();
tree.nrInOrderTraverse();
System.out.println("后续遍历");
//tree.nrPostOrderTraverse();
tree.postOrderTraverse();
tree.nrPostOrderTraverse();
System.out.println("先序遍历");
tree.preOrderTraverse();
tree.nrPreOrderTraverse();
//
}
}
Ⅵ 二叉树的层次遍历算法
二叉树的层次遍历算法有如下三种方法:
给定一棵二叉树,要求进行分层遍历,每层的节点值单独打印一行,下图给出事例结构:
之后大家就可以自己画图了,下面给出程序代码:
[cpp] view plain
void print_by_level_3(Tree T) {
vector<tree_node_t*> vec;
vec.push_back(T);
int cur = 0;
int end = 1;
while (cur < vec.size()) {
end = vec.size();
while (cur < end) {
cout << vec[cur]->data << " ";
if (vec[cur]->lchild)
vec.push_back(vec[cur]->lchild);
if (vec[cur]->rchild)
vec.push_back(vec[cur]->rchild);
cur++;
}
cout << endl;
}
}
最后给出完成代码的测试用例:124##57##8##3#6##
[cpp] view plain
#include<iostream>
#include<vector>
#include<deque>
using namespace std;
typedef struct tree_node_s {
char data;
struct tree_node_s *lchild;
struct tree_node_s *rchild;
}tree_node_t, *Tree;
void create_tree(Tree *T) {
char c = getchar();
if (c == '#') {
*T = NULL;
} else {
*T = (tree_node_t*)malloc(sizeof(tree_node_t));
(*T)->data = c;
create_tree(&(*T)->lchild);
create_tree(&(*T)->rchild);
}
}
void print_tree(Tree T) {
if (T) {
cout << T->data << " ";
print_tree(T->lchild);
print_tree(T->rchild);
}
}
int print_at_level(Tree T, int level) {
if (!T || level < 0)
return 0;
if (0 == level) {
cout << T->data << " ";
return 1;
}
return print_at_level(T->lchild, level - 1) + print_at_level(T->rchild, level - 1);
}
void print_by_level_1(Tree T) {
int i = 0;
for (i = 0; ; i++) {
if (!print_at_level(T, i))
break;
}
cout << endl;
}
void print_by_level_2(Tree T) {
deque<tree_node_t*> q_first, q_second;
q_first.push_back(T);
while(!q_first.empty()) {
while (!q_first.empty()) {
tree_node_t *temp = q_first.front();
q_first.pop_front();
cout << temp->data << " ";
if (temp->lchild)
q_second.push_back(temp->lchild);
if (temp->rchild)
q_second.push_back(temp->rchild);
}
cout << endl;
q_first.swap(q_second);
}
}
void print_by_level_3(Tree T) {
vector<tree_node_t*> vec;
vec.push_back(T);
int cur = 0;
int end = 1;
while (cur < vec.size()) {
end = vec.size();
while (cur < end) {
cout << vec[cur]->data << " ";
if (vec[cur]->lchild)
vec.push_back(vec[cur]->lchild);
if (vec[cur]->rchild)
vec.push_back(vec[cur]->rchild);
cur++;
}
cout << endl;
}
}
int main(int argc, char *argv[]) {
Tree T = NULL;
create_tree(&T);
print_tree(T);
cout << endl;
print_by_level_3(T);
cin.get();
cin.get();
return 0;
}
Ⅶ 什么是树的层次遍历 要求通俗易懂
就是按层(深度)遍历整棵树。
如果层次遍历这棵树,得到的序列就是12345678,遍历时因为要一层一层的下来,所以一般用广度优先遍历。
遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
设L、D、R分别表示遍历左子树、访问根结点和遍历右子树, 则对一棵二叉树的遍历有三种情况:DLR(称为先根次序遍历),LDR(称为中根次序遍历),LRD (称为后根次序遍历)。
(7)java二叉树的层次遍历扩展阅读:
二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。如果不考虑连通性,允许图中有多个连通分量。
给定N个节点,能构成h(N)种不同的二叉树。h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i。
Ⅷ java 递归 算 二叉树 层级
层次遍历从方法上不具有递归的形式,所以一般不用递归实现。当然了,非要写成递归肯定也是可以的,大致方法如下。 void LevelOrder(BTree T, int cnt) { BTree level = malloc(sizeof(struct BTNode)*cnt); if(level==NULL) return; int i=0,rear=0; if(cnt==0) return; for(i=0; i<cnt; i++){ printf("%c ",T[i].data); if(T[i].lchild) level[rear++]=*T[i].lchild; if(T[i].rchild) level[rear++]=*T[i].rchild; } printf("\n"); LevelOrder(level, rear); free(level); } 补充一下,在main里面调用的时候就得用LevelOrder(T,1)了。
Ⅸ 遍历二叉树
遍历方案:
1.遍历方案
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
(1)访问结点本身(N),
(2)遍历该结点的左子树(L),
(3)遍历该结点的右子树(R)。
以上三种操作有六种执行次序:
NLR、LNR、LRN、NRL、RNL、RLN。
注意:
前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。
2.三种遍历的命名
根据访问结点操作发生位置命名:
① NLR:前序遍历(PreorderTraversal亦称(先序遍历))
——访问结点的操作发生在遍历其左右子树之前。
② LNR:中序遍历(InorderTraversal)
——访问结点的操作发生在遍历其左右子树之中(间)。
③ LRN:后序遍历(PostorderTraversal)
——访问结点的操作发生在遍历其左右子树之后。
注意:
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。
遍历算法
1.中序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
(1)遍历左子树;
(2)访问根结点;
(3)遍历右子树。
2.先序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
(1) 访问根结点;
(2) 遍历左子树;
(3) 遍历右子树。
3.后序遍历得递归算法定义:
若二叉树非空,则依次执行如下操作:
(1)遍历左子树;
(2)遍历右子树;
(3)访问根结点。
4.中序遍历的算法实现
用二叉链表做为存储结构,中序遍历算法可描述为:
void InOrder(BinTree T)
{ //算法里①~⑥是为了说明执行过程加入的标号
① if(T) { // 如果二叉树非空
② InOrder(T->lchild);
③ printf("%c",T->data); // 访问结点
④ InOrder(T->rchild);
⑤ }
⑥ } // InOrder
遍历序列
1.遍历二叉树的执行踪迹
三种递归遍历算法的搜索路线相同(如下图虚线所示)。
具体线路为:
从根结点出发,逆时针沿着二叉树外缘移动,对每个结点均途径三次,最后回到根结点。
2.遍历序列
A
/ \
B C
/ / \
D E F
图
(1) 中序序列(inorder traversal)
中序遍历二叉树时,对结点的访问次序为中序序列
【例】中序遍历上图所示的二叉树时,得到的中序序列为:
D B A E C F
(2) 先序序列(preorder traversal)
先序遍历二叉树时,对结点的访问次序为先序序列
【例】先序遍历上图所示的二叉树时,得到的先序序列为:
A B D C E F
(3) 后序序列(postorder traversal)
后序遍历二叉树时,对结点的访问次序为后序序列
【例】后序遍历上图所示的二叉树时,得到的后序序列为:
D B E F C A
(4)层次遍历(level traversal)二叉树的操作定义为:若二叉树为空,则退出,否则,按照树的结构,从根开始自上而下,自左而右访问每一个结点,从而实现对每一个结点的遍历
注意:
(1)在搜索路线中,若访问结点均是第一次经过结点时进行的,则是前序遍历;若访问结点均是在第二次(或第三次)经过结点时进行的,则是中序遍历(或后序遍历)。只要将搜索路线上所有在第一次、第二次和第三次经过的结点分别列表,即可分别得到该二叉树的前序序列、中序序列和后序序列。
(2)上述三种序列都是线性序列,有且仅有一个开始结点和一个终端结点,其余结点都有且仅有一个前趋结点和一个后继结点。为了区别于树形结构中前趋(即双亲)结点和后继(即孩子)结点的概念,对上述三种线性序列,要在某结点的前趋和后继之前冠以其遍历次序名称。
【例】上图所示的二叉树中结点C,其前序前趋结点是D,前序后继结点是E;中序前趋结点是E,中序后继结点是F;后序前趋结点是F,后序后继结点是A。但是就该树的逻辑结构而言,C的前趋结点是A,后继结点是E和F。
二叉链表的构造
1. 基本思想
基于先序遍历的构造,即以二叉树的先序序列为输入构造。
注意:
先序序列中必须加入虚结点以示空指针的位置。
【例】
建立上图所示二叉树,其输入的先序序列是:ABD∮∮∮CE∮∮F∮∮。
2. 构造算法
假设虚结点输入时以空格字符表示,相应的构造算法为:
void CreateBinTree (BinTree *T)
{ //构造二叉链表。T是指向根指针的指针,故修改*T就修改了实参(根指针)本身
char ch;
if((ch=getchar())=='') *T=NULL; //读人空格,将相应指针置空
else{ //读人非空格
*T=(BinTNode *)malloc(sizeof(BinTNode)); //生成结点
(*T)->data=ch;
CreateBinTree(&(*T)->lchild); //构造左子树
CreateBinTree(&(*T)->rchild); //构造右子树
}
}
注意:
调用该算法时,应将待建立的二叉链表的根指针的地址作为实参。
【例】
设root是一根指针(即它的类型是BinTree),则调用CreateBinTree(&root)后root就指向了已构造好的二叉链表的根结点。
二叉树建立过程见http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/erchashujianli.htm
下面是关于二叉树的遍历、查找、删除、更新数据的代码(递归算法):
[code]
#include <iostream>
using namespace std;
typedef int T;
class bst{
struct Node{
T data;
Node* L;
Node* R;
Node(const T& d, Node* lp=NULL, Node* rp=NULL):data(d),L(lp),R(rp){}
};
Node* root;
int num;
public:
bst():root(NULL),num(0){}
void clear(Node* t){
if(t==NULL) return;
clear(t->L);
clear(t->R);
delete t;
}
~bst(){clear(root);}
void clear(){
clear(root);
num = 0;
root = NULL;
}
bool empty(){return root==NULL;}
int size(){return num;}
T getRoot(){
if(empty()) throw "empty tree";
return root->data;
}
void travel(Node* tree){
if(tree==NULL) return;
travel(tree->L);
cout << tree->data << ' ';
travel(tree->R);
}
void travel(){
travel(root);
cout << endl;
}
int height(Node* tree){
if(tree==NULL) return 0;
int lh = height(tree->L);
int rh = height(tree->R);
return 1+(lh>rh?lh:rh);
}
int height(){
return height(root);
}
void insert(Node*& tree, const T& d){
if(tree==NULL)
tree = new Node(d);
else if(ddata)
insert(tree->L, d);
else
insert(tree->R, d);
}
void insert(const T& d){
insert(root, d);
num++;
}
Node*& find(Node*& tree, const T& d){
if(tree==NULL) return tree;
if(tree->data==d) return tree;
if(ddata)
return find(tree->L, d);
else
return find(tree->R, d);
}
bool find(const T& d){
return find(root, d)!=NULL;
}
bool erase(const T& d){
Node*& pt = find(root, d);
if(pt==NULL) return false;
combine(pt->L, pt->R);
Node* p = pt;
pt = pt->R;
delete p;
num--;
return true;
}
void combine(Node* lc, Node*& rc){
if(lc==NULL) return;
if(rc==NULL) rc = lc;
else combine(lc, rc->L);
}
bool update(const T& od, const T& nd){
Node* p = find(root, od);
if(p==NULL) return false;
erase(od);
insert(nd);
return true;
}
};
int main()
{
bst b;
cout << "input some integers:";
for(;;){
int n;
cin >> n;
b.insert(n);
if(cin.peek()=='\n') break;
}
b.travel();
for(;;){
cout << "input data pair:";
int od, nd;
cin >> od >> nd;
if(od==-1&&nd==-1) break;
b.update(od, nd);
b.travel();
}
}
[/code]
Ⅹ java层次遍历算法思路
找个例子看一下就有了。比如递归前序遍历二叉树,即先根遍历。先遍历根节点,之后向下又是一个跟节点,在遍历做节点,在遍历右节点,依次下去,知道没有右节点结束。在遍历右边的部分,根节点,左节点,右节点,知道没有右节点是为止。至此遍历结束。书上有图一看就知道了。其他的遍历按照遍历算法一样。建议看下数据结构的遍历,讲的很详细。