赞
踩
二叉树的定义:
二叉树是
n(n≥0)
个结点的有限集,它或者是空集(n=0)
,或者由一个根结点及两棵互不相交的、分别称作这个根的左子树和右子树的二叉树组成。这是二叉树的递归定义。
二叉树的遍历:
所谓遍历,是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题
对于二叉树的遍历,可进一步分为三种:
①前序遍历(根左右):对于每一棵子树,先访问该节点,然后是左子树,最后是右子树
②中序遍历(左根右):对于每一棵子树,先访问左子树,然后是该节点,最后是右子树
③后序遍历(左右根):对于每一棵子树,先访问左子树,然后是右子树,最后是该节点
其中递归是实现上三种遍历逻辑最简单的方式
本关任务:完成用二叉链表存储的二叉树的前序遍历算法。
preOrder(TreeNode root)
方法,实现二叉树的前序遍历功能,并输出结点的值。本关要求我们实现二叉树的前序遍历,我们根据递归来实现根左右的遍历方式
- package step1;
-
- /**
- * Created by zengpeng on 2018/2/9.
- */
- public class BinaryTree {
-
- private TreeNode root;//根节点
-
- public BinaryTree() {
- root = null;
- }
-
- public void preOrder(TreeNode root) {
- /********** Begin *********/
- //递归实现 根左右
- if(root==null){
- return;
- }
- System.out.println(root.item);
- preOrder(root.leftChild);
- preOrder(root.rightChild);
-
- /********** End *********/
- }
-
- /**
- *以数组arr的数据,依次从上至下,从左至右构建一颗二叉树
- *
- * @param arr
- * @param n
- * @return
- */
- public TreeNode createTree(int arr[]) {
- TreeNode tmp[] = new TreeNode[arr.length + 1];
- for (int k = 1; k <= arr.length; k++) {
- TreeNode node = new TreeNode(arr[k - 1]);
- tmp[k] = node;
- if (k == 1) {
- root = node;
- } else {
- int j = k / 2;
- if (k % 2 == 0) {
- tmp[j].leftChild = node;
- } else {
- tmp[j].rightChild = node;
- }
- }
- }
-
- return root;
- }
-
- public static class TreeNode {
- private TreeNode leftChild;
- private TreeNode rightChild;
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
-
- }
本关任务:实现以二叉链表存储的二叉树的中序遍历算法。
补全inOrder(TreeNode root)
方法,实现二叉树的中序遍历功能,并输出结点的值
本关要求我们实现二叉树的中序遍历,我们根据递归来实现左根右的遍历方式
- package step2;
-
- /**
- * Created by zengpeng on 2018/2/12.
- */
- public class BinaryTree {
-
- private TreeNode root;//根节点
-
- public BinaryTree() {
- root = null;
- }
-
- public void inOrder(TreeNode root) {
- /********** Begin *********/
- //递归实现 左根右
- if(root==null){
- return;
- }
- inOrder(root.leftChild);
- System.out.println(root.item);
- inOrder(root.rightChild);
-
- /********** End *********/
- }
-
- /**
- * 以数组arr的数据,依次从上至下,从左至右构建一颗二叉树
- *
- * @param arr
- * @param n
- * @return
- */
- public TreeNode createTree(int arr[]) {
- TreeNode tmp[] = new TreeNode[arr.length + 1];
- for (int k = 1; k <= arr.length; k++) {
- TreeNode node = new TreeNode(arr[k - 1]);
- tmp[k] = node;
- if (k == 1) {
- root = node;
- } else {
- int j = k / 2;
- if (k % 2 == 0) {
- tmp[j].leftChild = node;
- } else {
- tmp[j].rightChild = node;
- }
- }
- }
-
- return root;
- }
-
- public static class TreeNode {
- private TreeNode leftChild;
- private TreeNode rightChild;
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
- }
本关任务:实现以二叉链表存储的二叉树的后序遍历算法。
postOrder(TreeNode root)
方法,实现后序遍历功能,并输出结点值。本关要求我们实现二叉树的后序遍历,我们根据递归来实现左右根的遍历方式
- package step3;
-
- /**
- * Created by zengpeng on 2018/2/12.
- */
- public class BinaryTree {
- private TreeNode root;//根节点
-
- public BinaryTree() {
- root = null;
- }
-
- public void postOrder(TreeNode root) {
- /********** Begin *********/
- //递归实现 左右根
- if(root==null){
- return;
- }
- postOrder(root.leftChild);
- postOrder(root.rightChild);
- System.out.println(root.item);
-
- /********** End *********/
- }
-
- /**
- * 以数组arr的数据,依次从上至下,从左至右构建一颗二叉树
- *
- * @param arr
- * @param n
- * @return
- */
- public TreeNode createTree(int arr[]) {
- TreeNode tmp[] = new TreeNode[arr.length + 1];
- for (int k = 1; k <= arr.length; k++) {
- TreeNode node = new TreeNode(arr[k - 1]);
- tmp[k] = node;
- if (k == 1) {
- root = node;
- } else {
- int j = k / 2;
- if (k % 2 == 0) {
- tmp[j].leftChild = node;
- } else {
- tmp[j].rightChild = node;
- }
- }
- }
-
- return root;
- }
-
- public static class TreeNode {
- private TreeNode leftChild;
- private TreeNode rightChild;
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
- }
本关任务:构建一棵二叉搜索树,向其中添加结点。
BSTree
类的对象;insert(int key)
方法,向树中添加结点;preOrder()
方法执行前序遍历;inOrder()
方法执行中序遍历;postOrder()
方法执行后序遍历; 二叉搜索树(binary search tree)
,又称二叉排序树,它或者是空树,或者是满足如下性质的二叉树:
本关要求我们实现二叉树的插入操作insert
首先我们来分析BSTree类中已经给我们了的方法
首先就是节点类TreeNode:其中该类是BSTree的静态内部类,外部类可直接调用该内部类的成员变量和方法
- //节点内部类
- public static class TreeNode {
- private TreeNode leftChild;//左孩子
- private TreeNode rightChild;//右孩子
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
然后就是BSTree的成员变量以及方法:一个成员变量root表示该树的根节点,空参的构造方法表示构建一个空树;然后是三种基本的遍历方式
题目要求我们补全插入节点的代码
我们根据二叉搜索树的性质,我们从根节点root开始一直向下寻找合适的插入位置,若插入的节点小于比较的节点,那么我们就向比较节点的左孩子处向下寻找;若插入的节点大于比较的节点,那么我们就向比较节点的右孩子处向下寻找,直到找到合适的位置
- package step1;
-
- /**
- * Created by zengpeng on 2018/3/3.
- */
- public class BSTree {
-
- private TreeNode root;//根结点
-
- public BSTree() {
- root = null;
- }
-
- /**
- * 向树root中插入key
- *
- * @param key 要插入的值
- */
- public void insert(int key) {
- /********** Begin *********/
- TreeNode newnode=new TreeNode(key);
- if(root==null){//树为空,要插入的节点即为根节点
- root=newnode;
- }else{
- TreeNode cur=root;
- while(cur!=null){
- if(cur.item==key){//已经存在
- return;
- }else if(key<cur.item){//在该节点的左边
- if(cur.leftChild==null){
- cur.leftChild=newnode;
- }else{//继续向左找
- cur=cur.leftChild;
- }
- }else if(key>cur.item){//在该节点的右边
- if(cur.rightChild==null){
- cur.rightChild=newnode;
- }else{//继续向右找
- cur=cur.rightChild;
- }
- }
- }
- }
-
- /********** End *********/
- }
-
- //前序遍历
- public void preOrder() {
- preOrder(root);
- }
- //中序遍历
- public void inOrder() {
- inOrder(root);
- }
- //后序遍历
- public void postOrder(){
- postOrder(root);
- }
-
- private void preOrder(TreeNode node) {
- if (node != null) {
- System.out.print(node.item + " ");
- preOrder(node.leftChild);
- preOrder(node.rightChild);
- }
- }
-
- private void inOrder(TreeNode node) {
- if (node != null) {
- inOrder(node.leftChild);
- System.out.print(node.item + " ");
- inOrder(node.rightChild);
- }
- }
-
- private void postOrder(TreeNode node) {
- if (node != null) {
- postOrder(node.leftChild);
- postOrder(node.rightChild);
- System.out.print(node.item + " ");
- }
- }
-
- //节点内部类
- public static class TreeNode {
- private TreeNode leftChild;
- private TreeNode rightChild;
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
- }
本关任务是:实现二叉搜索树的删除功能
BSTree
类的对象;insert(int key)()
方法,构建一棵二叉搜索树;delete(int key)
方法,删除元素key
;从一棵二叉搜索树T
中删除一个结点z
的整个策略可分为三个基本情况:
z
没有孩子结点,那么只是简单地将它删除,并修改它的父结点;z
只有一个孩子结点,那么将这个孩子提升到树中z
的位置上,并修改z
的父结点,使其指向z
的孩子结点;z
有两个孩子,那么找z右子树的最小节点代替z,最后删除替换后的最小节点
我们可以观察到,在第三种情况下(删除节点有左右两个节点),当我们将删除节点右子树的最小节点代替删除节点后,我们还需删除替换后的最小节点位置,但此时删除的情况就是情况一,二的一种,那么我们就可以从第三种情况开始,若存在第三种情况,那么我们就可以将其转化为第一二种情况的一种
那么具体怎么操作呢?以下图为例:
首先要删除一个节点,就要知道它的父节点以及其孩子节点,因此首先我们要先找到删除节点的父节点
然后我们从第三种情况开始考虑:找到删除节点右子树的最小节点并与删除节点替换,将其转换为一二种情况
那么此时要删除的节点以及其父节点就变了,我们要重新记录
最后我们就要寻找删除节点的孩子节点,并将其父节点与其孩子节点相连,这样就完成了节点的删除,但我们需要考虑的是,若删除的是根节点,那么我们就直接返回其孩子节点即可,不用再更改其父节点的指针了(根节点的父节点为null)
当然特殊情况(parent==null)不会包括第三种情况,因为经转化后删除节点必定有父节点;因此该特殊情况只存在于第一二中
- package step2;
-
- /**
- * Created by zengpeng on 2018/3/14.
- */
- public class BSTree {
- private TreeNode root;//根结点
-
- public BSTree() {
- root = null;
- }
-
- /**
- * 向树root中插入a
- *
- * @param key 要插入的值
- */
- public void insert(int key) {
- TreeNode x = root;
- TreeNode p = null;//始终指向x的父结点
- while (x != null) {
- p = x;
- if (key < x.item) {
- x = x.leftChild;
- } else {
- x = x.rightChild;
- }
- }
- if (null == p) {//空树
- root = new TreeNode(key);
- } else if (key < p.item) {
- p.leftChild = new TreeNode(key);
- } else {
- p.rightChild = new TreeNode(key);
- }
- }
-
- /**
- * 在树root中删除结点key
- *
- * @param key
- * @return
- */
- public void delete(int key) {
- root = delete(root, key);
- }
-
- private TreeNode delete(TreeNode x, int key) {
- /********** Begin *********/
- //三种情况
- TreeNode cur=x;
- TreeNode parent=null;
- while(x!=null && x.item!=key){
- parent=x;
- if(key<x.item){
- x=x.leftChild;
- }else{
- x=x.rightChild;
- }
- }
- //删除节点不存在
- if(x==null) return cur;
- //第三种情况:将删除节点与其右子树最小节点交换,并删除交换后的最小节点
- if(x.leftChild!=null && x.rightChild!=null){
- TreeNode mininode=x.rightChild;
- TreeNode miniparent=x;
- while(mininode.leftChild!=null){
- miniparent=mininode;
- mininode=mininode.leftChild;
- }
- //删除交换后的最小节点位置,转化为其他两种情况
- x.item=mininode.item;
- parent=miniparent;
- x=mininode;
- }
- //最后两种情况,找删除节点的孩子节点
- TreeNode child;
- if(x.rightChild!=null){
- child=x.rightChild;
- }else if(x.leftChild!=null){
- child=x.leftChild;
- }else{
- child=null;
- }
- //删除的是根节点
- if(parent==null) return child;
- //删除节点
- if(parent.leftChild==x){
- parent.leftChild=child;
- }else if(parent.rightChild==x){
- parent.rightChild=child;
- }
-
- return cur;
-
-
-
- /********** End *********/
- }
-
- /**
- * 删除树x中的最小结点
- *
- * @param x
- * @return
- */
- private TreeNode deleteMin(TreeNode x) {
- if (x.leftChild == null) return x.rightChild;
- x.leftChild = deleteMin(x.leftChild);
- return x;
- }
-
- /**
- * 查找树x中的最小结点
- *
- * @param x
- * @return
- */
- private TreeNode min(TreeNode x) {
- TreeNode p = x;
- while (p.leftChild != null) {
- p = p.leftChild;
- }
- return p;
- }
-
- public void preOrder() {
- preOrder(root);
- }
-
- private void preOrder(TreeNode node) {
- if (node != null) {
- System.out.print(node.item + " ");
- preOrder(node.leftChild);
- preOrder(node.rightChild);
- }
- }
-
- public void inOrder() {
- inOrder(root);
- }
-
- private void inOrder(TreeNode node) {
- if (node != null) {
- inOrder(node.leftChild);
- System.out.print(node.item + " ");
- inOrder(node.rightChild);
- }
- }
-
- public void postOrder() {
- postOrder(root);
- }
-
- private void postOrder(TreeNode node) {
- if (node != null) {
- postOrder(node.leftChild);
- postOrder(node.rightChild);
- System.out.print(node.item + " ");
- }
- }
-
-
- public static class TreeNode {
- private TreeNode leftChild;
- private TreeNode rightChild;
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
- }
本关任务:实现二叉搜索树的查找功能,如果指定的元素x
存在树中则返回true
,否则返回false
。
BSTree
类的对象;insert(int key)
方法,构建一棵二叉搜索树;preOrder()
方法,输出删除操作前树中的结点;delete(int key)
方法,删除最先添加的结点和最后添加的结点;preOrder()
方法,输出删除操作后树中的结点;search(int key)
方法,测试原来的结点哪些还在树中;根据二叉搜索树的性质,小了向左,大了向右,直到找到
- package step3;
-
- /**
- * Created by zengpeng on 2018/3/14.
- */
- public class BSTree {
- private TreeNode root;//根结点
-
- public BSTree() {
- root = null;
- }
-
- /**
- * 向树root中插入a
- *
- * @param key 要插入的值
- */
- public void insert(int key) {
- TreeNode x = root;
- TreeNode p = null;//始终指向x的父结点
- while (x != null) {
- p = x;
- if (key < x.item) {
- x = x.leftChild;
- } else {
- x = x.rightChild;
- }
- }
- if (null == p) {//空树
- root = new TreeNode(key);
- } else if (key < p.item) {
- p.leftChild = new TreeNode(key);
- } else {
- p.rightChild = new TreeNode(key);
- }
- }
-
- /**
- * 判断树root中是否包含key,包含则返回true,不包含返回false
- *
- * @param key
- * @return
- */
- public boolean search(int key) {
- /********** Begin *********/
- TreeNode p = root;
- //小了向左,大了向右
- while (p != null && key != p.item) {
- if (key < p.item) {
- p = p.leftChild;
- } else {
- p = p.rightChild;
- }
- }
- if (p == null) {
- return false;
- } else {
- return true;
- }
- /********** End *********/
- }
-
-
- /**
- * 在树root中删除结点key
- *
- * @param key
- * @return
- */
- public void delete(int key) {
- root = delete(root, key);
- }
-
- private TreeNode delete(TreeNode x, int key) {
- if (x == null) {
- return null;
- }
-
- if (key < x.item) {
- x.leftChild = delete(x.leftChild, key);
- } else if (key > x.item) {
- x.rightChild = delete(x.rightChild, key);
- } else {
- if (x.leftChild == null) return x.rightChild;
- if (x.rightChild == null) return x.leftChild;
- TreeNode t = x;
- x = min(t.rightChild);
- x.rightChild = deleteMin(t.rightChild);
- x.leftChild = t.leftChild;
- }
-
- return x;
- }
-
- /**
- * 删除树x中的最小结点
- * @param x
- * @return
- */
- private TreeNode deleteMin(TreeNode x) {
- if (x.leftChild == null) return x.rightChild;
- x.leftChild = deleteMin(x.leftChild);
- return x;
- }
-
- /**
- * 查找树x中的最小结点
- *
- * @param x
- * @return
- */
- private TreeNode min(TreeNode x) {
- TreeNode p = x;
- while (p.leftChild != null) {
- p = p.leftChild;
- }
- return p;
- }
-
- public void preOrder() {
- preOrder(root);
- }
-
- public void inOrder() {
- inOrder(root);
- }
-
- public void postOrder() {
- postOrder(root);
- }
-
- private void preOrder(TreeNode node) {
- if (node != null) {
- System.out.print(node.item + " ");
- preOrder(node.leftChild);
- preOrder(node.rightChild);
- }
- }
-
- private void inOrder(TreeNode node) {
- if (node != null) {
- inOrder(node.leftChild);
- System.out.print(node.item + " ");
- inOrder(node.rightChild);
- }
- }
-
- private void postOrder(TreeNode node) {
- if (node != null) {
- postOrder(node.leftChild);
- postOrder(node.rightChild);
- System.out.print(node.item + " ");
- }
- }
-
-
- public static class TreeNode {
- private TreeNode leftChild;
- private TreeNode rightChild;
- private int item;
-
- public TreeNode(int item) {
- this(null, null, item);
- }
-
- public TreeNode(TreeNode leftChild, TreeNode rightChild, int item) {
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- this.item = item;
- }
- }
- }
本关任务:向二叉树中插入左叶子节点,请补全insertLeft(T x, Node<T> parent)
函数实现插入左叶子节点的功能
我们主要看本关已经给出的insertRight方法,本关要求我们补全插入左子节点的方法,这与insertRight思路逻辑一致,我们只需稍微更改一下孩子的指向即可
- //在当前二叉树的parent节点中插入一个新的左子结点,若已存在左子树,则将该左子树变成新左子结点的右子树
- public boolean insertLeft(T x, Node<T> parent)
- {
- /********* Begin *********/
- if(parent==null) return false;
- Node<T> p=new Node<>(x);
- if(parent.lChild==null){
- parent.lChild=p;
- }else{
- p.rChild=parent.lChild;
- parent.lChild=p;
- }
- return true;
- /********* End *********/
- }
- //在当前二叉树的parent节点中插入一个新的右子结点,若已存在右子树,则将该右子树变成新右子结点的左子树
- public boolean insertRight(T x, Node<T> parent)
- {
- if(parent==null) return false;
- Node<T> p= new Node<T>(x);
- if(parent.rChild==null) parent.rChild = p;
- else
- {
- p.rChild = parent.rChild;
- parent.rChild = p;
- }
- return true;
- }
具体了解二叉搜索树请参考下面文章:
https://blog.csdn.net/m0_74808313/article/details/130103168
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。