`
luoweifu
  • 浏览: 63300 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

二叉树(1)——二叉树的定义和递归实现

 
阅读更多


定义


最多有两棵子树的有序树,称为二叉树。二叉树是一种特殊的

递归定义:二叉树是n(n>=0)个有限结点构成的集合。N=0称为空二叉树;n>0的二叉树由一个根结点和两互不相交的,分别称为左子树和右子树的二叉树构成。

二叉树中任何结点的第1个子树称为其左子树,左子树的根称为该结点的左孩子;二叉树中任何结点的第2个子树称为其右子树,左子树的根称为该结点的右孩子。如下图是一个二叉树:

图1.二叉树

满二叉树和完全二叉树

在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且叶子结点都在同一层上,这样的二叉树称作满二叉树。一棵深度为k且由2k-1个结点的二叉树称为满二叉树。

如果一棵具有n个结点的二叉树的结构与满二叉树的前n个结点的结构相同,这样的二叉树称作完全二叉树

图2. 满二叉树和完全二叉树


基本性质


这里规定二叉树的根结点的层次为1。

性质1:则二叉树的第i 层最多有2i-1个结点(在此二叉树的层次从1开始,i≥1)

性质2:深度为k的二叉树最多有2k-1个结点。(k≥1)

性质3:对任何一棵二叉树T, 如果其叶结点个数为n0, 度为2的非叶结点个数为n2, 则有

n0 = n2 + 1

性质4:具有 n(n>0)个结点的完全二叉树的深度为⎣log2n⎦+1;⎦x⎦表示不超过x的最大整数。

性质5:如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到第⎣l og2n⎦ +1层,每层从左到右),则对任一结点i(1≤i≤n),有:

(1)如果i=1,则结点i无双亲,是二叉树的根;如果i>1,则其双亲是结点⎣i/2⎦。

(2) 如果2i<=n, 则结点i的左孩子结点是2i;否则,结点i为叶子结点,无左孩子结点。

(3)如果2i+1<=n,则结点i的右孩子是结点2i+1; 否则,结点i为叶子结点,无右孩子结点。


抽象数据类型


数据元素:具有相同特性的数据元素的集合。

结构关系:树中数据元素间的结构关系由二叉树的定义确定。

基本操作:树的主要操作有

(1)创建树IntTree(&T)

(2)销毁树DestroyTree(&T)

(3)构造树CreatTree(&T,deinition)

(4)置空树ClearTree(&T)

(5)判空树TreeEmpty(T)

(6)求树的深度TreeDepth(T)

(7)获得树根Root(T)

(8)获取结点Value(T,cur_e,&e),将树中结点cur_e存入e单元中。

(9)数据赋值Assign(T,cur_e,value),将结点value,赋值于树T的结点cur_e中。

(10)获得双亲Parent(T,cur_e),返回树T中结点cur_e的双亲结点。

(11)获得最左孩子LeftChild(T,cur_e),返回树T中结点cur_e的最左孩子。

(12)获得右兄弟RightSibling(T,cur_e),返回树T中结点cur_e的右兄弟。

(13)插入子树InsertChild(&T,&p,i,c),将树c插入到树T中p指向结点的第i个子树之前。

(14)删除子树DeleteChild(&T,&p,i),删除树T中p指向结点的第i个子树。

(15)遍历树TraverseTree(T,visit())

二叉树的实现


二叉树接口BTree

package datastructure.tree.btree;

public interface BTree {
	/**
	 * 添加左子树
	 * @param lChild 左子树
	 */
	public void addLeftTree(BTree lChild);
	/**
	 * 添加右子树
	 * @param rchild 右子树
	 */
	public void addRightTree(BTree rchild) ;
	/**
	 * 置空树
	 */
	public void clearTree();
	/**
	 * 求树的深度
	 * @return 树的深度
	 */
	public int dept();
	/**
	 * 求左孩子 结点
	 * @return
	 */
	public BTree getLeftChild();
	
	/**
	 * 求右孩子结点
	 * @return
	 */
	public BTree getRightChild();
	/**
	 * 获得根结点的数据
	 * @return
	 */
	public Object getRootData();
	/**
	 * 是否有左子树
	 * @return
	 */
	public boolean hasLeftTree();
	/**
	 * 是否有右子树
	 * @return
	 */
	public boolean hasRightTree();
	/**
	 * 判断是否为空树
	 * @return 如果为空,返回true,否则返回false
	 */
	public boolean isEmpty();
	/**
	 * 判断是否为叶子结点
	 * @return
	 */
	public boolean isLeaf();
	/**
	 * 删除左子树
	 */
	public void removeLeftChild();
	/**
	 * 删除右子树
	 */
	public void removeRightChild();
	/**
	 * 获得树根
	 * @return 树的根
	 */
	public BTree root();
	/**
	 * 设置根结点的数据
	 */
	public void setRootData(Object data);
	/**
	 * 求结点数
	 * @return 结点的个数 
	 */
	public int size();
}

二叉链表的实现

package datastructure.tree.btree;

public class LinkBTree implements BTree {
	private Object data;
	private BTree lChild;
	private BTree rChild;
	
	public LinkBTree() {
		this.clearTree();
	}
	public LinkBTree(Object data) {
		this.data = data;
		this.lChild = null;
		this.rChild = null;
	}
	@Override
	public void addLeftTree(BTree lChild) {
		this.lChild = lChild;
	}

	@Override
	public void addRightTree(BTree rChild) {
		this.rChild = rChild;
	}

	@Override
	public void clearTree() {
		this.data = null;
		this.lChild = null;
		this.rChild = null;
	}

	@Override
	public int dept() {
		return dept(this);
	}
	
	private int dept(BTree btree) {
		if(btree.isEmpty()) {
			return 0;
		}else if(btree.isLeaf()) {
			return 1;
		} else {
			if(btree.getLeftChild() == null) {
				return dept(btree.getRightChild()) + 1;
			} else if(btree.getRightChild() == null) {
				return dept(btree.getLeftChild()) + 1;
			} else {
				return Math.max(dept(btree.getLeftChild()), dept(btree.getRightChild()))+1;
			}
		}
	}

	@Override
	public BTree getLeftChild() {
		return lChild;
	}


	@Override
	public BTree getRightChild() {
		return rChild;
	}

	@Override
	public Object getRootData() {
		return data;
	}

	@Override
	public boolean hasLeftTree() {
		if(lChild != null)
			return true;
		return false;
	}

	@Override
	public boolean hasRightTree() {
		if(rChild != null)
			return true;
		return false;
	}

	@Override
	public boolean isEmpty() {
		if((lChild == null && rChild == null && data == null) || this == null) {
			return true;
		}
		return false;
	}
	
	@Override
	public boolean isLeaf() {
		if(lChild == null && rChild == null) {
			return true;
		}
		return false;
	}

	@Override
	public void removeLeftChild() {
		lChild = null;
	}

	@Override
	public void removeRightChild() {
		rChild = null;
	}
	@Override
	public BTree root() {
		return this;
	}
	@Override
	public void setRootData(Object data) {
		this.data = data;
	}
	@Override
	public int size() {
		return size(this);
	}
	private int size(BTree btree) {
		if(btree == null) 
			return 0;
		else if(btree.isLeaf()) 
			return 1;
		else {
			if(btree.getLeftChild() == null) {
				return size(btree.getRightChild()) + 1;
			} else if(btree.getRightChild() == null) {
				return size(btree.getLeftChild()) + 1;
			} else {
				return size(btree.getLeftChild()) + size(btree.getRightChild()) + 1;
			}
		} 
	}
	

}


二叉树的遍历

二叉树的遍历是指按照一定的次序访问树中所有结点,并且每个结点只被访问一次的过程。通常的遍历有三种方式,分别是:前序遍历、中序遍历和后序遍历,假设根结点、左孩子结点和右孩子结点分别用D、R、L表示,则前序遍历、中序遍历和后序遍历的顺序分别为DLR、LDR、LRD。所谓访问某结点,一般指对结点中的数据进行某种操作。所以,我们可以定义一个对结点中的数据进行操作的接口Visit,让所有遍历树的类实现这个接口。

Visit接口:

package datastructure.tree;
/**
 * 对结点进行操作的接口
 * @author Administrator
 *
 */
public interface Visit {
	/**
	 * 对结点进行某种操作
	 * @param btree 树的结点
	 */
	public void visit(BTree btree);
}

遍历二叉树


package datastructure.tree;
/**
 * 遍历二叉树
 * @author Administrator
 *
 */
public class OrderBTree implements Visit{
	/**
	 * 前序遍历
	 * @param root 根结点
	 */
	public void preOrder(BTree root) {
		visit(root);
		if(root.getLeftChild() != null) {
			preOrder(root.getLeftChild());
		}
		if(root.getRightChild() != null) {
			preOrder(root.getRightChild());
		}
	}
	/**
	 * 中序遍历
	 * @param root 根结点
	 */
	public void inOrder(BTree root) {
		if(root.getLeftChild() != null)
			inOrder(root.getLeftChild());
		visit(root);
		if(root.getRightChild() != null) {
			//System.out.println("true");
			inOrder(root.getRightChild());
		}
	}
	/**
	 * 后序遍历
	 * @param root 根结点
	 */
	public void postOrder(BTree root) {
		if(root.getLeftChild() != null)
			postOrder(root.getLeftChild());
		if(root.getRightChild() != null)
			postOrder(root.getRightChild());
		visit(root);
	}

	@Override
	public void visit(BTree btree) {
		System.out.print(btree.getRootData() + "\t");
	}

}

二叉树的测试


要构建的树

package datastructure.tree;
/**
 * 测试二叉树
 * @author Administrator
 *
 */
public class BTreeTest {
	public static void main(String args[]) {
		BTree btree = new LinkBTree('A');
		BTree bt1, bt2, bt3, bt4;
		bt1 = new LinkBTree('B');
		btree.addLeftTree(bt1);
		bt2 = new LinkBTree('D');
		bt1.addLeftTree(bt2);
		
		bt3 =  new LinkBTree('C');
		btree.addRightTree(bt3);
		bt4 =  new LinkBTree('E');
		bt3.addLeftTree(bt4);
		bt4 =  new LinkBTree('F');
		bt3.addRightTree(bt4);
		
		System.out.println("树的深度:" + btree.dept());
		System.out.println("树的结点数:" + btree.size());
		System.out.println("是否为空树:" + btree.isEmpty());
		System.out.println("是否为叶子结点:" + btree.isLeaf());
		System.out.println("最左下边结点是否为叶子结点:" + btree.getRightChild().getRightChild().isLeaf());
		System.out.println("root结点:" + btree.root());
		
		OrderBTree order = new OrderBTree();
		System.out.println("\n前序遍历:");
		order.preOrder(btree);
		System.out.println("\n中序遍历:");
		order.inOrder(btree);
		System.out.println("\n后序遍历:");
		order.postOrder(btree);
		
		btree.removeLeftChild();
		System.out.println("\n删除左子树后中序遍历为:");
		order.inOrder(btree);
	}
}

结果如下:

树的深度:3
树的结点数:6
是否为空树:false
是否为叶子结点:false
最左下边结点是否为叶子结点:true
root结点:datastructure.tree.LinkBTree@dc8569


前序遍历:
A B DCEF
中序遍历:
D B AECF
后序遍历:
D B EFCA
删除左子树后中序遍历为:
A E CF

分享到:
评论

相关推荐

    二叉树的遍历——递归以及非递归实现

    vs2010下运行编写,使用了STL栈,实现了基本的插入、删除、计算深度、查找,主要是遍历,包括递归遍历,以及非递归的前序中序后序遍历,每个函数都有测试用例,如果存在错误,请在给我留言。

    链表先序建立二叉树,得到中序后序输出,递归和非递归实现(C++代码加设计报告)

    在本课程设计中,我们将探讨如何使用C++编程语言来构建和操作二叉树,特别是通过先序遍历建立二叉树以及非递归方式实现中序遍历。这一过程涉及到了数据结构中的核心概念——二叉链表,以及递归和非递归算法的应用。 ...

    二叉树的操作--递归非递归遍历、结点个数、树深度

    先序递归遍历二叉树: a b c 先序非递归遍历二叉树: a b c 中序递归遍历二叉树: b a c 中序非递归遍历二叉树: b a c 后序递归遍历二叉树: b c a 后序非递归遍历二叉树: b c a 二叉树的深度是2 二叉树的结点个数...

    c语言 二叉树应用:创建、递归非递归遍历、计算结点、分支、交换子树

    可实现: 输入相应元素,用先序创建二叉树(无元素处用“#”) 递归先序遍历二叉树: 递归中序遍历二叉树: 递归后序遍历二叉树: 非递归先序遍历二叉树: 非递归中序遍历二叉树: 非递归后序遍历二叉树: ...

    二叉树递归和非递归遍历以及层次构建节点数为n的二叉树

    递归实现 二种非递归实现 二叉树中序遍历: 递归实现 非递归实现 二叉树后序遍历: 递归实现 非递归实现 二叉树层次遍历 二叉树层次创建,创建方法遵循卡特兰数 http://write.blog.csdn.net/postedit/17380455

    c++编写二叉树遍历(前中后序——递归与非递归)

    本主题主要探讨的是在C++中如何实现二叉树的前序、中序和后序遍历,同时包括递归和非递归两种方法。VS2008是Microsoft Visual Studio的一个版本,它提供了一个强大的开发环境,支持C++编程。 **前序遍历**: 前序...

    数据结构实验——二叉树的建立和遍历.zip

    2.用递归及非递归算法对二叉树实现先序遍历; 3.用递归及非递归算法对二叉树实现中序遍历; 4.用递归及非递归算法对二叉树实现后序遍历。 5.用递归遍历算法中的访问结点的操作修改为叶结点计数,统计度为0的;度为1...

    数据结构实用教程之二叉树,其中包含了:二叉树的定义、二叉树的递归遍历、二叉树基本操作。

    数据结构实用教程之二叉树,其中包含了:二叉树的定义、二叉树的递归遍历、二叉树基本操作。 数据结构实用教程之二叉树,其中包含了:二叉树的定义、二叉树的递归遍历、二叉树基本操作。 数据结构实用教程之二叉树,...

    c语言,二叉树,前中后,递归,非递归

    根据给定的信息,本文将详细解释二叉树的遍历方法,包括递归与非递归方式下的前序、中序、后序遍历,并简要介绍层次遍历的概念。 ### 二叉树简介 二叉树是一种常用的数据结构,其中每个节点最多有两个子节点,通常...

    数据结构二叉树遍历递归,非递归

    在本主题中,我们将深入探讨二叉树的三种主要遍历方法:中序遍历、前序遍历和后序遍历,以及如何通过递归和非递归的方式实现这些遍历。 首先,让我们理解递归遍历的概念。递归是一种解决问题的方法,它将问题分解为...

    二叉树应用——计算表达式[参照].pdf

    作者定义了一个节点类和一个栈类,然后使用这些类来实现二叉树的构建和计算表达式。这种方法可以使得代码更加灵活和可维护。 这个文件展示了一种使用二叉树来计算表达式的方法。作者使用了栈来实现二叉树的构建,并...

    二叉树的形成和三种非递归遍历

    二叉树也是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态: (1)空二叉树——(a); (2)只有一个根结点的二叉树——(b); (3)右子树为空的二叉树——(c); (4)左子树为空的二叉树——(d); (5)完全...

    C语言实现二叉树的前序遍历(非递归)

    1. **定义结构体**:`struct BiTNode` 定义了二叉树的节点结构,包含数据域`data`,以及指向左右子节点的指针`lchild`和`rchild`。 2. **前序创建树**:`later`函数通过输入字符序列来构建二叉树。当输入字符为`' '...

    二叉树遍历——前中后序

    `二叉树遍历.cpp`、`二叉树遍历终结版.cpp`、`二叉树遍历更简单.cpp` 这些文件可能是不同版本的C++代码实现,可能包含不同的算法优化或者改进,比如使用迭代而非递归,或者利用双端队列(deque)来简化后序遍历的...

    二叉树的遍历(递归+非递归 c语言版)

    本篇文章将详细介绍这三种遍历方法,并通过C语言实现递归和非递归版本。 1. 前序遍历(根-左-右) 在前序遍历中,我们首先访问根节点,然后遍历左子树,最后遍历右子树。递归实现非常直观,代码如下: ```c void...

    二叉树的遍历的非递归算法(C++模板实现)

    使用C++模板、类的技术实现了二叉树的中序遍历,在BC3.1已经测试成功

    数据结构 二叉树三种遍历的非递归算法(背诵版).doc

    本篇文章将深入探讨二叉树三种主要遍历方式(前序、中序、后序)的非递归算法实现,力求让读者能够清晰地理解和掌握这些算法,并在实践中加以应用。 **前序遍历**是二叉树遍历的一种基本形式,其遍历顺序是先访问根...

    设计程序实现二叉树结点的类型定义和对二叉树的基本操作

    设计程序实现二叉树结点的类型定义和对二叉树的基本操作。 1. **按先序次序建立一个二叉树** - 这一步骤涉及二叉树的构建过程,通常从根节点开始,按照先序的方式依次添加左右子树。 - 使用递归方法实现构建过程...

    二叉树的遍历方法和递归实现

    以C#为例,我们可以定义一个`LinkBiTree&lt;T&gt;`类来实现二叉树的基本操作,并在其内部定义递归函数来实现遍历。 递归实现的关键在于递归调用自身来处理左右子树,同时根据不同的遍历类型调整访问节点的时机。例如,在...

    java实现的二叉树的递归和非递归遍历

    二叉树遍历的递归和非递归实现都有其优缺点。递归方法代码简洁,但会消耗更多的系统资源,因为每次函数调用都会产生一定的开销。非递归方法虽然代码相对复杂,但能有效地控制内存使用,适合处理大容量的数据。 在...

Global site tag (gtag.js) - Google Analytics