先按树-二叉树-二叉查找树的顺序解释会比较清楚。

一,树

树(Tree)是n(n≥0)个结点的有限集。在任意一棵非空树中:

(1)有且仅有一个特定的被称为根(Root)的结点;

(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。

结点的度(Degree):结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶子(Leaf)或终端结点。度不为0的结点称为非终端结点或分支结点。
树的度:是树内各结点的度的最大值。
孩子和双亲:结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)。
结点的层次(Level):是从根结点开始计算起,根为第一层,根的孩子为第二层,依次类推。树中结点的最大层次称为树的深度(Depth)或高度。

如果将树中结点的各子树看成从左至右是有次序的(即不能互换),则称该树为有序树,否则称为无序树。

二,二叉树

二叉树(Binary Tree)的特点是每个结点至多具有两棵子树(即在二叉树中不存在度大于2的结点),并且子树之间有左右之分。

二叉树的性质:
(1)、在二叉树的第i层上至多有2i-1个结点(i≥1)。
(2)、深度为k的二叉树至多有2k-1个结点(k≥1)。
(3)、对任何一棵二叉树,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。

有很多关于树的术语,在这里不做过多的文字解释,不想画图了。下面我找了图来说明,图参考来自http://blog.csdn.net/u012152619/article/details/42059325,通过它可以直观地理解树的路径、根、父节点、子节点、叶节点、子树、层等概念

三,二叉查找树(左<中<右)

我们从一种特殊的、使用很广泛的二叉树入手:二叉查找树。

二叉查找树的性质:

(1)、若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;
(2)、若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;
(3)、它的左、右子树也分别为二叉查找树。
用一句话概括,二叉查找树的特点是,一个节点的左子节点的关键字值小于这个节点,右子节点的关键字值大于或等于这个父节点。

二叉查找树的基本操作是查找,插入,删除,遍历,下面一一介绍:

1,查找(search)

我们已经知道,二叉搜索树的特点是左子节点小于父节点,右子节点大于或等于父节点。查找某个节点时,先从根节点入手,如果该元素值小于根节点,则转向左子节点,否则转向右子节点,以此类推,直到找到该节点,或者到最后一个叶子节点依然没有找到,则证明树中没有该节点

代码是:

  /** 查找元素,返回true */public boolean search(E e) {TreeNode<E> current = root; // 从根元素开始while (current != null) {if (e.compareTo(current.element) < 0) {//如果比当前元素值小,就指向当前元素的左子树current = current.left;}else if (e.compareTo(current.element) > 0) {//如果比当前元素值大,就指向当前元素的右子树current = current.right;}else // element等于 current.elementreturn true; //发现元素,返回true}return false;}

2,插入(insert)

插入一个新节点首先要确定插入的位置,关键思路是确定新节点父节点所在的位置。

代码:

/** 插入元素,成功返回true */public boolean insert(E e) {if (root == null)root = createNewNode(e); // 如果是树空则创造一个跟节点else {// 标记当前父节点位置TreeNode<E> parent = null;TreeNode<E> current = root;while (current != null)if (e.compareTo(current.element) < 0) {parent = current;current = current.left;}else if (e.compareTo(current.element) > 0) {parent = current;current = current.right;}elsereturn false; // 有重复节点,不能被插入// 创建一个新节点挂在父节点下if (e.compareTo(parent.element) < 0)parent.left = createNewNode(e);elseparent.right = createNewNode(e);}size++;return true; // 插入成功}

3,删除(delete)
删除BST中的一个节点是最麻烦的操作,总结一下大概下面两种方法:

Case 1:删除点没有左孩子,这是只需要将该节点的父节点和当前节点的有孩子相连即可

Case2:删除点有左孩子.这种情况下先找到当前节点的左子树的最右节点,因为一个节点的左子树的最右节点也比右子树的最左节点小,把最右节点复制给删除点,然后删除最右节点

代码:

 /** 删除节点,删除成功返回true,不在树中返回false*/public boolean delete(E e) {// 标记被删除的节点和该节点的父节点位置TreeNode<E> parent = null; TreeNode<E> current = root;while (current != null) {if (e.compareTo(current.element) < 0) {parent = current;current = current.left;}else if (e.compareTo(current.element) > 0) {parent = current;current = current.right;}elsebreak; // 元素在这个树中}if (current == null)return false; // 元素不在树中if (current.left == null) { // 第一种情况:元素没有左子树,把当前节点的右子树直接挂在其父节点的右子树上// 把当前节点的右子树直接挂在其父节点的右子树上if (parent == null) {root = current.right;}else {if (e.compareTo(parent.element) < 0)parent.left = current.right;elseparent.right = current.right;}}else {  // 第二种情况:元素有左子树,先找到当前节点的左子树的最右节点//标记当前节点的左子树的父节点和最右节点TreeNode<E> parentOfRightMost = current;TreeNode<E> rightMost = current.left;//一直向右,找到最右端的节点,因为一个节点的左子树的最右节点也比右子树的最左节点小while (rightMost.right != null) {parentOfRightMost = rightMost;rightMost = rightMost.right; // 一直向右}/** 以上代码的目的是要找到删除节点的左子树最右节点 ,因为一个节点的左子树的最右节点也比右子树的最左节点小*/// 找到最右节点后,放到当前要删除的位置current.element = rightMost.element;// 消除最右节点if (parentOfRightMost.right == rightMost)parentOfRightMost.right = rightMost.left;//把最右节点的左子树挂在其父节点的右子树上else// 具体情况: parentOfRightMost == currentparentOfRightMost.left = rightMost.left;     }size--;return true; // 删除成功}

下面介绍一下二叉树的构成:

Tree.java

package com.hust.cn;
public interface Tree<E extends Comparable<E>> {//查找元素 public boolean search(E e);//插入元素public boolean insert(E e);//删除元素public boolean delete(E e);//中序遍历public void inorder();//后序遍历public void postorder();//前序遍历public void preorder();//返回大小public int getSize();//判空public boolean isEmpty();//返回树的迭代器public java.util.Iterator iterator();
}

AbstractTree.java

package com.hust.cn;
public abstract class AbstractTree<E extends Comparable<E>>implements Tree<E> {//中序遍历public void inorder() {}//后序遍历public void postorder() {}//前序遍历public void preorder() {}//判空public boolean isEmpty() {return getSize() == 0;}//返回树的迭代器public java.util.Iterator iterator() {return null;}
}

BinaryTree.java

package com.hust.cn;
public class BinaryTree<E extends Comparable<E>>extends AbstractTree<E> {protected TreeNode<E> root;//节点类,是内部类protected int size = 0;/** 构造函数 */public BinaryTree() {}/** 对象数组创建一个二叉查找树 */public BinaryTree(E[] objects) {for (int i = 0; i < objects.length; i++)insert(objects[i]);}/** 查找元素,返回true */public boolean search(E e) {TreeNode<E> current = root; // 从根元素开始while (current != null) {if (e.compareTo(current.element) < 0) {//如果比当前元素值小,就指向当前元素的左子树current = current.left;}else if (e.compareTo(current.element) > 0) {//如果比当前元素值大,就指向当前元素的右子树current = current.right;}else // element等于 current.elementreturn true; //发现元素,返回true}return false;}/** 插入元素,成功返回true */public boolean insert(E e) {if (root == null)root = createNewNode(e); // 如果是树空则创造一个跟节点else {// 标记当前父节点位置TreeNode<E> parent = null;TreeNode<E> current = root;while (current != null)if (e.compareTo(current.element) < 0) {parent = current;current = current.left;}else if (e.compareTo(current.element) > 0) {parent = current;current = current.right;}elsereturn false; // 有重复节点,不能被插入// 创建一个新节点挂在父节点下if (e.compareTo(parent.element) < 0)parent.left = createNewNode(e);elseparent.right = createNewNode(e);}size++;return true; // 插入成功}/*创建一个新节点*/protected TreeNode<E> createNewNode(E e) {return new TreeNode<E>(e);}/** 中序遍历*/public void inorder() {inorder(root);}/** 从根节点中序遍历 ,递归方法*/protected void inorder(TreeNode<E> root) {if (root == null) return;inorder(root.left);System.out.print(root.element + " ");inorder(root.right);}/**后序遍历 */public void postorder() {postorder(root);}/**从根节点后序遍历,递归方法 */protected void postorder(TreeNode<E> root) {if (root == null) return;postorder(root.left);postorder(root.right);System.out.print(root.element + " ");}/**前序遍历 */public void preorder() {preorder(root);}/** 从根节点前序遍历,递归方法 */protected void preorder(TreeNode<E> root) {if (root == null) return;System.out.print(root.element + " ");preorder(root.left);preorder(root.right);}/** 返回树的大小 */public int getSize() {return size;}/** 返回根节点 */public TreeNode getRoot() {return root;}/** 返回从根节点到一个具体元素的路径 */public java.util.ArrayList<TreeNode<E>> path(E e) {java.util.ArrayList<TreeNode<E>> list =new java.util.ArrayList<TreeNode<E>>();//用数组存放路径上的元素TreeNode<E> current = root; // 从根节点开始while (current != null) {list.add(current); // 添加当前元素到数组里if (e.compareTo(current.element) < 0) {current = current.left;}else if (e.compareTo(current.element) > 0) {current = current.right;}elsebreak;}return list; // 返回节点数组}/** 删除节点,删除成功返回true,不在树中返回false*/public boolean delete(E e) {// 标记被删除的节点和该节点的父节点位置TreeNode<E> parent = null; TreeNode<E> current = root;while (current != null) {if (e.compareTo(current.element) < 0) {parent = current;current = current.left;}else if (e.compareTo(current.element) > 0) {parent = current;current = current.right;}elsebreak; // 元素在这个树中}if (current == null)return false; // 元素不在树中if (current.left == null) { // 第一种情况:元素没有左子树,把当前节点的右子树直接挂在其父节点的右子树上// 把当前节点的右子树直接挂在其父节点的右子树上if (parent == null) {root = current.right;}else {if (e.compareTo(parent.element) < 0)parent.left = current.right;elseparent.right = current.right;}}else {  // 第二种情况:元素有左子树,先找到当前节点的左子树的最右节点//标记当前节点的左子树的父节点和最右节点TreeNode<E> parentOfRightMost = current;TreeNode<E> rightMost = current.left;//一直向右,找到最右端的节点,因为一个节点的左子树的最右节点也比右子树的最左节点小while (rightMost.right != null) {parentOfRightMost = rightMost;rightMost = rightMost.right; // 一直向右}/** 以上代码的目的是要找到删除节点的左子树最右节点 ,因为一个节点的左子树的最右节点也比右子树的最左节点小*/// 找到最右节点后,放到当前要删除的位置current.element = rightMost.element;// 消除最右节点if (parentOfRightMost.right == rightMost)parentOfRightMost.right = rightMost.left;//把最右节点的左子树挂在其父节点的右子树上else// 具体情况: parentOfRightMost == currentparentOfRightMost.left = rightMost.left;     }size--;return true; // 删除成功}/** 获得中序迭代器 */public java.util.Iterator iterator() {return inorderIterator();}/**  创建一个迭代器类*/public java.util.Iterator inorderIterator() {return new InorderIterator();}// 中序迭代器类,内部类class InorderIterator implements java.util.Iterator {// 存储元素的数组private java.util.ArrayList<E> list =new java.util.ArrayList<E>();private int current = 0; //数组中当前元素的位置public InorderIterator() {inorder(); // 中序遍历二叉树}/** 从根部中序遍历*/private void inorder() {inorder(root);}/** 中序遍历子树 */private void inorder(TreeNode<E> root) {if (root == null)return;inorder(root.left);list.add(root.element);inorder(root.right);}/** 遍历下一个元素*/public boolean hasNext() {if (current < list.size())return true;return false;}/** 获得当前元素,并把指针指向另一个元素 */public Object next() {return list.get(current++);}/** 移出当前元素 */public void remove() {delete(list.get(current)); //删除当前元素list.clear(); //清理数组inorder(); //重新中序遍历数组}}/** 清楚树的所有元素 */public void clear() {root = null;size = 0;}/** 内部类,树的节点类 */public static class TreeNode<E extends Comparable<E>> {E element;TreeNode<E> left;TreeNode<E> right;public TreeNode(E e) {element = e;}}}

TestBinaryTree.java

package com.hust.cn;
public class TestBinaryTree {public static void main(String[] args) {// 创建一个二叉查找树BinaryTree<String> tree = new BinaryTree<String>();tree.insert("George");tree.insert("Michael");tree.insert("Tom");tree.insert("Adam");tree.insert("Jones");tree.insert("Peter");tree.insert("Daniel");// 遍历树System.out.println("Inorder (sorted): ");tree.inorder();System.out.println("\nPostorder: ");tree.postorder();System.out.println("\nPreorder: ");tree.preorder();System.out.println("\nThe number of nodes is " + tree.getSize());// 查找一个元素System.out.println("\nIs Peter in the tree? " + tree.search("Peter"));// 从root到peter的一条路径System.out.println("\nA path from the root to Peter is: ");java.util.ArrayList<BinaryTree.TreeNode<String>>  path = tree.path("Peter");for (int i = 0; path != null && i < path.size(); i++)System.out.print(path.get(i).element + " ");//利用数组构建一个二叉查找树,并中序遍历Integer[] numbers = {2, 4, 3, 1, 8, 5, 6, 7};BinaryTree<Integer> intTree = new BinaryTree<Integer>(numbers);System.out.println("\nInorder (sorted): ");intTree.inorder();}
}

测试结果:

数据结构-二叉树和二叉查找树相关推荐

  1. 数据结构(二叉树、二叉查找树、平衡二叉树、红黑树)

    #博学谷IT学习技术支持# 文章目录 数据结构 1. 二叉树 二叉树的特点 二叉树结构图 2. 二叉查找树 二叉查找树的特点 二叉查找树结构图 二叉查找树和二叉树对比结构图 二叉查找树添加节点规则 3 ...

  2. 数据结构 - 二叉树 - 面试中常见的二叉树算法题

    数据结构 - 二叉树 - 面试中常见的二叉树算法题 数据结构是面试中必定考查的知识点,面试者需要掌握几种经典的数据结构:线性表(数组.链表).栈与队列.树(二叉树.二叉查找树.平衡二叉树.红黑树).图 ...

  3. 数据结构与算法--二叉查找树转顺序排列双向链表

    二叉查找树转顺序排列双向链表 题目:输入一颗二叉查找树,将二叉查找树转成一个排序的双向链表,要求不能创建任何新节点,只调整树节点中指针的指向.例如下图所示: 本次二叉查找树节点定义使用之前文章 数据结 ...

  4. 数据结构与算法--二叉查找树实现原理

    二叉查找树 二叉树的一个重要应用就是他在查询中的使用,假设书中每个节点存储一项数据.在我们的案例中,任意复杂的项在java中都容易处理,但为了简单还是假设都是整数.还假设他们都是不重复的整数,使二叉树 ...

  5. 怎样将树的中序遍历的数输入到一个数组中_数据结构与算法-二叉查找树平衡(DSW)...

    上一节探讨了二叉查找树的基本操作,二叉查找树的查找效率在理想状态下是O(lgn),使用该树进行查找总是比链表快得多.但是,该论点并不总是正确,因为查找效率和二叉树的形状息息相关.就像这样: 图1-1给 ...

  6. 括号表示法字符串构造二叉树_一篇文章学会二叉树和二叉查找树

    树是计算机科学中经常用到的一种数据结构.树是一种非线性的数据结构,以分层的方式存储数据. 树被用来存储具有层级关系的数据,比如文件系统中的文件. 树还可以用来存储有序列表. 树的定义 树是由一组以边连 ...

  7. 数据结构——二叉树总结

    数据结构-二叉树总结 写在前面 二叉树遍历 递归实现先.中.后序遍历 非递归遍历 先序非递归 中序非递归 后序非递归 层次遍历 二叉树还原 先序中序建树 后序中序建树 层次中序建树 二叉树应用 二叉查 ...

  8. 3. 数据结构--二叉树 BST AVL树 Huffman

    数据结构–二叉树 KEY:(不敢相信没有堆-) 二叉树的定义及其主要特征 ☑️ 二叉树的顺序存储结构和链式存储结构实现 二叉树的遍历及应用 二叉排序(查找.检索)树 (BST) 平衡的二叉检索树- A ...

  9. 数据结构树-->二叉查找树\二叉排序树

    目录 1. 数据结构树–>树基础 2. 数据结构树–>二叉树 3. 数据结构树–>二叉查找树\二叉排序树 4. 数据结构树–>平衡二叉树 5. 数据结构树–>霍夫曼树 6 ...

最新文章

  1. 802.11的隐藏节点和RTS,CTS机制
  2. 在使用模板时遇到的错误,TypeError at /index/ context must be a dict rather than RequestContext(亲测)
  3. 如何处理OData错误消息Property XX at offset XX is invalid
  4. jQuery 筛选
  5. 老司机做VR视频,需要什么样的全景相机?
  6. java printf 版本_java – PrintStream类型中的printf(String,Object ...
  7. 获取URL各项参数(Java)
  8. paip.css的覆盖
  9. BLE芯片商总结和市场趋势分析
  10. BadBoy安装与使用
  11. 2017 ACM-CCPC 秦皇岛站 总结
  12. Hadoop三大发行版本简单介绍
  13. 华为的计算机怎么没声音怎么办,笔记本电脑没有声音怎么办
  14. Javascript使用三大家族和事件来DIY动画效果相关笔记(六)
  15. mysql 性能优化,减轻数据库的压力。(减少数据库查询的次数)
  16. IMPL1. all_fanin/all_fanout命令解析
  17. Java 中代码优化的 30 个小技巧(中)
  18. pandas案例之消费金额和消费之间的关联与性别和吸烟与否的关系
  19. 旷厂练习生 Vol.15 | CV 小白在旷视 4 个月就能写顶会 paper?来听听机甲大师 Albert 的故事!...
  20. 解决audio: Failed to create voice `goldfish_audio'错误

热门文章

  1. C++ Primer 5th笔记(chap 18 大型程序工具)命名空间特性
  2. 解读“中国数字人民币的研发进展白皮书“
  3. Http接口设计(1)Token之前
  4. Bitcoin 中的挖矿算法(3) 挖矿算法代码说明
  5. wxWidgets 编译 ICON 资源
  6. Ubuntu报错记录(Could not get lock /var/lib/dpkg/lock-frontend问题的解决方法)
  7. 【网络安全】详细记录一道简单面试题的思路和方法
  8. C语言读入全都的文件内容2
  9. MySql 查询小数保留两位小数
  10. MySQL修改用户(RENAME USER)