一、数据结构分类
(一)按逻辑结构
- 集合(无辑关系)
- 线性结构(线性表):数组、链表、栈、队列
- 非线性结构:树、图、多维数组
(二)按存储结构
顺序(数组)储结构、链式储结构、索引储结构、散列储结构
二、二叉树相关性质
- 结点的度:一个结点的子树的个数记为该结点的度.
- 树的度:所有节点中度数最大的结节的度数,叶子节点的度为零。
- 树的高度:一棵树的最大层次数记为树的高度(或深度)。
- 有序(无序)树:若将树中结点的各子树看成是从左到右具有次序的,即不能交换,则称该树为有序树。否则称为无序树。
- 二叉树第i层(i≥1)上至多有2^(i-1)个节点。
- 深度为k的二叉树至多有2^k-1个节点(k≥1)。
- 对任何一棵二叉,若叶子节点数为n0,度为2的节点数为n2,则n0=n2+1。
- 具有n个节点的完全二叉树的深度为 (㏒2^n)(向下取整)+1。
- 对一棵有n个节点的完全二叉树的节点按层次从上到下,自左至右进行编号,则对任一节点i(1≤i≤n)有:若 i=1,则节点i是二叉树的根,无双亲;若 i>1,则其双亲为 i/2(向下取整)。若2i>n,则节点i没有孩子节点,否则其左孩子为2i。若2i+1>n,则节点i没有右孩子,否则其右孩子为2i+1。
- 若深度为k的二叉树有2^k-1个节点,则称其为满二叉树。满二叉树是一棵完全二叉树。
- 对于完全二叉树中,度为1的节点个数只可能为1个或0个。
- 对于二叉树,如果叶子节点数为n0,度为1的节点数为n1,度为2的节点数为n2,则节点总数n = n0 + n1 + n2。
- 对于任意树,总节点数 = 每个节点度数和 + 1
- 二叉树的高度等于根与最远叶节点(具有最多祖先的节点)之间分支数目。空树的高度是-1。只有单个元素的二叉树,其高度为0。
.
三、二叉树的遍历
遍历是按某种策略访问树中的每个节点,且仅访问一次。
(一) 二叉树结构实现
- package tree.bintree;
- /**
- * 创建 非完全二叉树、完全二叉树、满二叉树
- *
- * 由于二叉树的节点增加没有什么规则,所以这里只是简单的使用了递一
- * 次性把整棵树创建出来,而没有设计出一个一个添加节点的方法与删除
- *
- * @author jzj
- * @date 2009-12-23
- */
- public class BinTree {// Bin=Binary(二进位的, 二元的)
- protected Entry root;//根
- private int size;//树的节点数
- /**
- * 树的节点结构
- * @author jzj
- * @date 2009-12-23
- */
- protected static class Entry {
- int elem;//数据域,这里我们作为编号
- Entry left;//左子树
- Entry right;//右子树
- public Entry(int elem) {
- this.elem = elem;
- }
- public String toString() {
- return " number=" + elem;
- }
- }
- /**
- * 根据给定的节点数创建一个完全二叉树或是满二叉树
- * @param nodeCount 要创建节点总数
- */
- public void createFullBiTree(int nodeCount) {
- root = recurCreateFullBiTree(1, nodeCount);
- }
- /**
- * 递归创建完全二叉树
- * @param num 节点编号
- * @param nodeCount 节点总数
- * @return TreeNode 返回创建的节点
- */
- private Entry recurCreateFullBiTree(int num, int nodeCount) {
- size++;
- Entry rootNode = new Entry(num);//根节点
- //如果有左子树则创建左子树
- if (num * 2 <= nodeCount) {
- rootNode.left = recurCreateFullBiTree(num * 2, nodeCount);
- //如果还可以创建右子树,则创建
- if (num * 2 + 1 <= nodeCount) {
- rootNode.right = recurCreateFullBiTree(num * 2 + 1, nodeCount);
- }
- }
- return (Entry) rootNode;
- }
- /**
- * 根据给定的数组创建一棵树,这个棵树可以是完全二叉树也可是普通二叉树
- * 数组中为0的表示不创建该位置上的节点
- * @param nums 数组中指定了要创建的节点的编号,如果为0,表示不创建
- */
- public void createBinTree(int[] nums) {
- root = recurCreateBinTree(nums, 0);
- }
- /**
- * 递归创建二叉树
- * @param nums 数组中指定了要创建的节点的编号,如果为0,表示不创建
- * @param index 需要使用数组中的哪个元素创建节点,如果为元素为0,则不创建
- * @return TreeNode 返回创建的节点,最终会返回树的根节点
- */
- private Entry recurCreateBinTree(int[] nums, int index) {
- //指定索引上的编号不为零上才需创建节点
- if (nums[index] != 0) {
- size++;
- Entry rootNode = new Entry(nums[index]);//根节点
- //如果有左子树则创建左子树
- if ((index + 1) * 2 <= nums.length) {
- rootNode.left = (Entry) recurCreateBinTree(nums, (index + 1) * 2 - 1);
- //如果还可以创建右子树,则创建
- if ((index + 1) * 2 + 1 <= nums.length) {
- rootNode.right = (Entry) recurCreateBinTree(nums, (index + 1) * 2);
- }
- }
- return (Entry) rootNode;
- }
- return null;
- }
- public int size() {
- return size;
- }
- //取树的最左边的节点
- public int getLast() {
- Entry e = root;
- while (e.right != null) {
- e = e.right;
- }
- return e.elem;
- }
- //测试
- public static void main(String[] args) {
- //创建一个满二叉树
- BinTree binTree = new BinTree();
- binTree.createFullBiTree(15);
- System.out.println(binTree.size());//15
- System.out.println(binTree.getLast());//15
- //创建一个完全二叉树
- binTree = new BinTree();
- binTree.createFullBiTree(14);
- System.out.println(binTree.size());//14
- System.out.println(binTree.getLast());//7
- //创建一棵非完全二叉树
- binTree = new BinTree();
- int[] nums = new int[] { 1, 2, 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 7, 8 };
- binTree.createBinTree(nums);
- System.out.println(binTree.size());//8
- System.out.println(binTree.getLast());//8
- }
- }
package tree.bintree; /** * 创建 非完全二叉树、完全二叉树、满二叉树 * * 由于二叉树的节点增加没有什么规则,所以这里只是简单的使用了递一 * 次性把整棵树创建出来,而没有设计出一个一个添加节点的方法与删除 * * @author jzj * @date 2009-12-23 */ public class BinTree {// Bin=Binary(二进位的, 二元的) protected Entry root;//根 private int size;//树的节点数 /** * 树的节点结构 * @author jzj * @date 2009-12-23 */ protected static class Entry { int elem;//数据域,这里我们作为编号 Entry left;//左子树 Entry right;//右子树 public Entry(int elem) { this.elem = elem; } public String toString() { return " number=" + elem; } } /** * 根据给定的节点数创建一个完全二叉树或是满二叉树 * @param nodeCount 要创建节点总数 */ public void createFullBiTree(int nodeCount) { root = recurCreateFullBiTree(1, nodeCount); } /** * 递归创建完全二叉树 * @param num 节点编号 * @param nodeCount 节点总数 * @return TreeNode 返回创建的节点 */ private Entry recurCreateFullBiTree(int num, int nodeCount) { size++; Entry rootNode = new Entry(num);//根节点 //如果有左子树则创建左子树 if (num * 2 <= nodeCount) { rootNode.left = recurCreateFullBiTree(num * 2, nodeCount); //如果还可以创建右子树,则创建 if (num * 2 + 1 <= nodeCount) { rootNode.right = recurCreateFullBiTree(num * 2 + 1, nodeCount); } } return (Entry) rootNode; } /** * 根据给定的数组创建一棵树,这个棵树可以是完全二叉树也可是普通二叉树 * 数组中为0的表示不创建该位置上的节点 * @param nums 数组中指定了要创建的节点的编号,如果为0,表示不创建 */ public void createBinTree(int[] nums) { root = recurCreateBinTree(nums, 0); } /** * 递归创建二叉树 * @param nums 数组中指定了要创建的节点的编号,如果为0,表示不创建 * @param index 需要使用数组中的哪个元素创建节点,如果为元素为0,则不创建 * @return TreeNode 返回创建的节点,最终会返回树的根节点 */ private Entry recurCreateBinTree(int[] nums, int index) { //指定索引上的编号不为零上才需创建节点 if (nums[index] != 0) { size++; Entry rootNode = new Entry(nums[index]);//根节点 //如果有左子树则创建左子树 if ((index + 1) * 2 <= nums.length) { rootNode.left = (Entry) recurCreateBinTree(nums, (index + 1) * 2 - 1); //如果还可以创建右子树,则创建 if ((index + 1) * 2 + 1 <= nums.length) { rootNode.right = (Entry) recurCreateBinTree(nums, (index + 1) * 2); } } return (Entry) rootNode; } return null; } public int size() { return size; } //取树的最左边的节点 public int getLast() { Entry e = root; while (e.right != null) { e = e.right; } return e.elem; } //测试 public static void main(String[] args) { //创建一个满二叉树 BinTree binTree = new BinTree(); binTree.createFullBiTree(15); System.out.println(binTree.size());//15 System.out.println(binTree.getLast());//15 //创建一个完全二叉树 binTree = new BinTree(); binTree.createFullBiTree(14); System.out.println(binTree.size());//14 System.out.println(binTree.getLast());//7 //创建一棵非完全二叉树 binTree = new BinTree(); int[] nums = new int[] { 1, 2, 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 7, 8 }; binTree.createBinTree(nums); System.out.println(binTree.size());//8 System.out.println(binTree.getLast());//8 } }
(二)利用二叉树本身特点进行递归遍历(属内部遍历)
由于二叉树所具有的递归性质,一棵非空的二叉树可以看作是由根节点、左子树和右子树3部分构成,因为若能依次遍历这3部分的信息,也就遍历了整个二叉树。按照左子树的遍历在右子树的遍历之前进行的约定,根据访问根节点位置的不同,可以得到二叉的前序、中序、后序3种遍历方法。
- package tree.bintree;
- /**
- * 二叉树的三种 内部 遍历:前序、中序、后序
- * 但不管是哪种方式,左子树的遍历在右子树的遍历之前遍历是这有三种遍历方式都
- * 必须遵循的约定
- * @author jzj
- * @date 2009-12-23
- */
- public class BinTreeInOrder extends BinTree {
- /**
- * 节点访问者,可根据需要重写visit方法
- */
- static abstract class Visitor {
- void visit(Object ele) {
- System.out.print(ele + " ");
- }
- }
- public void preOrder(Visitor v) {
- preOrder(v, root);
- }
- /**
- * 树的前序递归遍历 pre=prefix(前缀)
- * @param node 要遍历的节点
- */
- private void preOrder(Visitor v, Entry node) {
- //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
- if (node != null) {
- v.visit(node.elem);//先遍历父节点
- preOrder(v, node.left);//再遍历左节点
- preOrder(v, node.right);//最后遍历右节点
- }
- }
- public void inOrder(Visitor v) {
- inOrder(v, root);
- }
- /**
- * 树的中序递归遍历 in=infix(中缀)
- * @param node 要遍历的节点
- */
- private void inOrder(Visitor v, Entry node) {
- //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
- if (node != null) {
- inOrder(v, node.left);//先遍历左节点
- v.visit(node.elem);//再遍历父节点
- inOrder(v, node.right);//最后遍历右节点
- }
- }
- public void postOrder(Visitor v) {
- postOrder(v, root);
- }
- /**
- * 树的后序递归遍历 post=postfix(后缀)
- * @param node 要遍历的节点
- */
- private void postOrder(Visitor v, Entry node) {
- //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
- if (node != null) {
- postOrder(v, node.left);//先遍历左节点
- postOrder(v, node.right);//再遍历右节点
- v.visit(node.elem);//最后遍历父节点
- }
- }
- //测试
- public static void main(String[] args) {
- //创建二叉树
- int[] nums = new int[] { 1, 2, 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 7, 8 };
- BinTreeInOrder treeOrder = new BinTreeInOrder();
- treeOrder.createBinTree(nums);
- System.out.print("前序遍历 - ");
- treeOrder.preOrder(new Visitor() {
- });
- System.out.println();
- System.out.print("中序遍历 - ");
- treeOrder.inOrder(new Visitor() {
- });
- System.out.println();
- System.out.print("后序遍历 - ");
- treeOrder.postOrder(new Visitor() {
- });
- /*
- * output:
- * 前序遍历 - 1 2 4 6 3 5 7 8
- * 中序遍历 - 4 6 2 1 3 7 5 8
- * 后序遍历 - 6 4 2 7 8 5 3 1
- */
- }
- }
package tree.bintree; /** * 二叉树的三种 内部 遍历:前序、中序、后序 * 但不管是哪种方式,左子树的遍历在右子树的遍历之前遍历是这有三种遍历方式都 * 必须遵循的约定 * @author jzj * @date 2009-12-23 */ public class BinTreeInOrder extends BinTree { /** * 节点访问者,可根据需要重写visit方法 */ static abstract class Visitor { void visit(Object ele) { System.out.print(ele + " "); } } public void preOrder(Visitor v) { preOrder(v, root); } /** * 树的前序递归遍历 pre=prefix(前缀) * @param node 要遍历的节点 */ private void preOrder(Visitor v, Entry node) { //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null if (node != null) { v.visit(node.elem);//先遍历父节点 preOrder(v, node.left);//再遍历左节点 preOrder(v, node.right);//最后遍历右节点 } } public void inOrder(Visitor v) { inOrder(v, root); } /** * 树的中序递归遍历 in=infix(中缀) * @param node 要遍历的节点 */ private void inOrder(Visitor v, Entry node) { //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null if (node != null) { inOrder(v, node.left);//先遍历左节点 v.visit(node.elem);//再遍历父节点 inOrder(v, node.right);//最后遍历右节点 } } public void postOrder(Visitor v) { postOrder(v, root); } /** * 树的后序递归遍历 post=postfix(后缀) * @param node 要遍历的节点 */ private void postOrder(Visitor v, Entry node) { //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null if (node != null) { postOrder(v, node.left);//先遍历左节点 postOrder(v, node.right);//再遍历右节点 v.visit(node.elem);//最后遍历父节点 } } //测试 public static void main(String[] args) { //创建二叉树 int[] nums = new int[] { 1, 2, 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 7, 8 }; BinTreeInOrder treeOrder = new BinTreeInOrder(); treeOrder.createBinTree(nums); System.out.print("前序遍历 - "); treeOrder.preOrder(new Visitor() { }); System.out.println(); System.out.print("中序遍历 - "); treeOrder.inOrder(new Visitor() { }); System.out.println(); System.out.print("后序遍历 - "); treeOrder.postOrder(new Visitor() { }); /* * output: * 前序遍历 - 1 2 4 6 3 5 7 8 * 中序遍历 - 4 6 2 1 3 7 5 8 * 后序遍历 - 6 4 2 7 8 5 3 1 */ } }
(三)二叉树的非递归遍历(属外部遍历)
1、利用栈与队列对二叉树进行非递归遍历
- package tree.bintree;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.Stack;
- /**
- * 二叉树的外部遍历:深度优先(先根)、广度(层次)优先遍历
- *
- * @author jzj
- * @date 2009-12-23
- */
- public class BinTreeOutOrder extends BinTree {
- /**
- * 二叉树深序优先遍历(即二叉树的先根遍历)迭代器,外部可以使用该迭代器
- * 进行非递归的遍历,这是一种在二叉树结构外部的一种遍历算法,它没有使用
- * 二叉树本身的结构特点(左右子树递归)进行递归遍历
- * @author jzj
- */
- private class DepthOrderIterator implements Iterator {
- //栈里存放的是每个节点
- private Stack stack = new Stack();
- public DepthOrderIterator(Entry node) {
- //根入栈,但在放入左右子节点前会马上出栈,即根先优于左右子节点访问
- stack.push(node);
- }
- //是否还有下一个元素
- public boolean hasNext() {
- if (stack.isEmpty()) {
- return false;
- }
- return true;
- }
- //取下一个元素
- public Entry next() {
- if (hasNext()) {
- //取栈顶元素
- Entry treeNode = (Entry) stack.pop();//先访问根
- if (treeNode.right != null) {
- stack.push(treeNode.right);//再放入右子节点
- }
- if (treeNode.left != null) {
- stack.push(treeNode.left);//最后放入左子节点,但访问先于右节点
- }
- // 返回遍历得到的节点
- return treeNode;
- } else {
- // 如果栈为空
- return null;
- }
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
- /**
- * 向外界提供先根遍历迭代器
- * @return Iterator 返回先根遍历迭代器
- */
- public Iterator createPreOrderItr() {
- return new DepthOrderIterator(root);
- }
- /**
- * 二叉树广度优先遍历迭代器,外部可以使用该迭代器
- * 进行非递归的遍历,这是一种在二叉树结构外部的一种遍历算法,它没有使用
- * 二叉树本身的结构特点(左右子树递归)进行递归遍历
- * @author jzj
- */
- private class LevelOrderIterator implements Iterator {
- //使用队列结构实现层次遍历,队列里存储的为节点
- private LinkedList queue = new LinkedList();
- public LevelOrderIterator(Entry node) {
- if (node != null) {
- //将根入队
- queue.addLast(node);
- }
- }
- //是否还有下一个元素
- public boolean hasNext() {
- if (queue.isEmpty()) {
- return false;
- }
- return true;
- }
- //取下一个元素
- public Entry next() {
- if (hasNext()) {
- //取栈顶迭元素
- Entry treeNode = (Entry) queue.removeFirst();
- if (treeNode.left != null) {//如果有左子树,加入有序列表中
- queue.addLast(treeNode.left);
- }
- if (treeNode.right != null) {//如果有右子树,加入有序列表中
- queue.addLast(treeNode.right);
- }
- // 返回遍历得到的节点
- return treeNode;
- } else {
- // 如果队列为空
- return null;
- }
- }
-
public void<
发表评论
相关推荐
通过本课题的设计与实现,不仅能够加深对二叉树及其遍历方法的理解,还能够在实践中提高编程技能。二叉树的应用非常广泛,包括搜索引擎中的文档索引、编译器中的语法树等。因此,熟练掌握二叉树的遍历技巧对于计算机...
了解各种遍历方式及其适用场景,有助于开发者设计出更为高效的算法。 - 不同的遍历方式可以应用于不同的问题场景,灵活运用这些遍历技巧可以在解决复杂问题时起到事半功倍的效果。 4. **提升编程能力**: - 实现...
按先序遍历的扩展序列建立二叉树的二叉链表存储结构,实现二叉树先序、中序、后序遍历的递归算法,实现二叉树中序遍历的非递归算法,实现二叉树层次遍历的非递归算法(要求使用顺序队列,调用顺序队列基本操作...
通过这次实验,学生不仅可以巩固和扩展关于二叉树及其遍历算法的知识,还能提高实际编程能力,学会如何使用循环队列等数据结构来解决实际问题。此外,通过亲手编写代码并调试运行,能够更深刻地理解理论知识与实际...
该程序实现了二叉树的存储,及其先序、中序和后序的遍历,还能够统计二叉树的叶子结点的个数。 二、设计内容 1. 数据结构 在本程序中,我们使用了二叉树结点结构体 BiTNode,包含了节点的内容(char 数据类型)和...
在探讨二叉树的遍历方法及其深度与结点数的计算之前,我们首先简要回顾一下二叉树的基本定义。二叉树是一种特殊的树结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树具有以下特点: 1. **...
二叉树的遍历及其操作
以上就是基于题目所给的信息对“二叉树的遍历算法”这一主题的详细介绍,包括了二叉树的定义、创建方法、遍历方式以及节点数量的统计等内容。这些知识点对于理解和掌握二叉树这一重要的数据结构具有重要的意义。
这种遍历方式常用于复制二叉树或者创建二叉树的镜像。 2. 中序遍历(左-根-右):首先递归地访问左子树,然后访问根节点,最后访问右子树。在二叉搜索树中,中序遍历可以得到有序序列。 3. 后序遍历(左-右-根):...
- **结论:** 通过本实验,成功实现了二叉树的多种遍历方法,并计算了二叉树的深度和叶子节点数量,加深了对二叉树及其遍历的理解。 - **改进建议:** - 进一步优化遍历算法的时间复杂度。 - 增加异常处理机制,...
本文将深入探讨二叉树的遍历方式及其应用,为读者提供对二叉树更全面的认识。 首先,我们需要明确什么是二叉树。二叉树是一种每个节点最多有两个子节点的数据结构,通常子节点被称作“左子节点”和“右子节点”。...
- 对于每种遍历方式,应输出相应的遍历序列,方便检查。 #### 六、总结 通过本次课程设计,学生不仅能够掌握二叉树的相关理论知识,还能在实践中锻炼自己的编程能力,学会如何使用面向对象的思维方式解决问题。...
### 数据结构:二叉树的遍历(C语言版) #### 一、引言 在计算机科学中,数据结构是...在实际应用中,二叉树及其遍历方法是非常重要的基础,掌握这些基本概念和技术对于深入理解高级数据结构和算法设计具有重要意义。
vs2010下运行编写,使用了STL栈,实现了基本的插入、删除、计算深度、查找,主要是遍历,包括递归遍历,以及非递归的前序中序后序遍历,每个函数都有测试用例,如果存在错误,请在给我留言。
综上所述,二叉树遍历是数据结构学习中的核心内容,通过实际的演示和报告,学生可以深入理解遍历方法及其在实际问题中的应用。在设计过程中,应注重代码的可读性和可维护性,同时培养问题解决和分析能力。
本话题主要涉及二叉树的遍历方法及其在特定情况下的应用。 二叉树的遍历主要有三种经典方法:前序遍历、中序遍历和后序遍历。这些遍历方法是理解二叉树特性和操作的关键。 1. **前序遍历**(Preorder Traversal)...
传统的二叉树遍历方法通常采用递归方式,即通过函数调用自身来处理子节点。然而,递归可能会导致调用栈过深,特别是在处理深度较大的二叉树时。非递归遍历,也称为迭代遍历,使用栈或者队列等数据结构来模拟递归过程...
二叉树的遍历是访问二叉树中的所有节点的过程,一般有三种遍历方式: - **前序遍历**:访问顺序为根节点→左子树→右子树。 - **中序遍历**:访问顺序为左子树→根节点→右子树。 - **后序遍历**:访问顺序为左子树...
在计算机科学领域中,数据结构是存储和组织数据的系统方法,而二叉树作为一种基础且重要的数据结构,在各种算法和程序设计中扮演着关键角色。...随着动画演示的直观体验,二叉树及其遍历技术的学习变得更加高效和有趣。
接下来,我们将详细讨论这些遍历方式及其原理。 1. **树的遍历**: - **前序遍历**:先访问根节点,然后遍历左子树,最后遍历右子树。在没有递归和迭代器的情况下,可以通过手动维护一个栈来模拟这个过程,首先将...