增删改查都挺快。
主要是看,父节点在哪里
编写程序
首先是节点
注意事项就是
使用this.left和this.right调动程序
package org.example.sort;
public class HeroNode {
public static int no;
public static String name;
public static HeroNode left;
public static HeroNode right;
public static int getNo() {
return no;
}
public static void setNo(int no) {
HeroNode.no = no;
}
public static String getName() {
return name;
}
public static void setName(String name) {
HeroNode.name = name;
}
public static HeroNode getLeft() {
return left;
}
public static void setLeft(HeroNode left) {
HeroNode.left = left;
}
public static HeroNode getRight() {
return right;
}
public static void setRight(HeroNode right) {
HeroNode.right = right;
}
@Override
public String toString() {
return "HeroNode{}";
}
public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
//前序遍历输出
System.out.print(this + " ");//输出自己然后向左
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
else if(this.right != null){
this.right.preOrder();
}
}
public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
//先不顾一切往左走,然后输出,然后往右走
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
System.out.print(this + " ");
if(this.right != null){
this.right.preOrder();
}
}
//先往左走,然后往右,最后输出
public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
if(this.right != null){
this.right.preOrder();
}
System.out.print(this + " ");
}
}
二叉树程序关键是要知道根节点
package org.example.sort;
public class BinaryTree {
private HeroNode root;
public HeroNode getRoot() {
return root;
}
public void setRoot(HeroNode root) {
this.root = root;
}
public void preOrder(){
if(root != null){
this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void midOrder(){
if(root != null){
this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void backOrder(){
if(root != null){
this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
}
左右子树的遍历
左右子树的查询节点
前序查找一个节点
package org.example.sort;
public class HeroNode {
public int no;
public String name;
public HeroNode left;
public HeroNode right;
public HeroNode(int no, String name, HeroNode left, HeroNode right) {
this.no = no;
this.name = name;
this.left = left;
this.right = right;
}
public HeroNode() {
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//这里一定要用this,因为每次动的都是不同的节点,每次this都不一样
public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
//前序遍历输出
System.out.print(this + " ");//输出自己然后向左
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
else if(this.right != null){
this.right.preOrder();
}
}
public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
System.out.print(this + " ");
if(this.right != null){
this.right.preOrder();
}
}
public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
if(this.right != null){
this.right.preOrder();
}
System.out.print(this + " ");
}
//前序遍历查找某个节点
public HeroNode preOrderSeacher(int no){
//先比较一下当前节点是不是
//这里一定要用this,
//无论如何都要返回一个东西,所以需要一个resultNode,实在不行返回Null
HeroNode resultNode = null;//用来返回结果
if(this.no == no){
resultNode = this;//
return resultNode;//找到了直接返回,代表循环结束了
}
if(this.left != null){
resultNode = this.left.preOrderSeacher(no);//进行遍历
}
if(resultNode != null){
//左边找到了,就不用看右边了
return resultNode;
}
if(this.right != null){
resultNode = this.right.preOrderSeacher(no);//向右遍历
}
return resultNode;//无论找到没都需要返回了
}
}
package org.example.sort;
public class BinaryTree {
private static HeroNode root;
public HeroNode getRoot() {
return root;
}
public void setRoot(HeroNode root) {
this.root = root;
}
public void preOrder(){
if(root != null){
this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void midOrder(){
if(root != null){
this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void backOrder(){
if(root != null){
this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void preOrderSeacher(int no){
//放进来一个数据
if(root != null){
HeroNode heroNode = root.preOrderSeacher( no);
if(heroNode == null){
System.out.println("没找到节点");
}
else
System.out.println(heroNode);
}
}
}
或者我让遍历查询代码更简单了。
package org.example.sort;
public class HeroNode {
public int no;
public String name;
public HeroNode left;
public HeroNode right;
public HeroNode(int no, String name, HeroNode left, HeroNode right) {
this.no = no;
this.name = name;
this.left = left;
this.right = right;
}
public HeroNode() {
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//这里一定要用this,因为每次动的都是不同的节点,每次this都不一样
public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
//前序遍历输出
System.out.print(this + " ");//输出自己然后向左
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
else if(this.right != null){
this.right.preOrder();
}
}
public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
System.out.print(this + " ");
if(this.right != null){
this.right.preOrder();
}
}
public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
if(this.right != null){
this.right.preOrder();
}
System.out.print(this + " ");
}
//前序遍历查找某个节点
public HeroNode preOrderSeacher(int no){
//先比较一下当前节点是不是
//这里一定要用this,
//无论如何都要返回一个东西,所以需要一个resultNode,实在不行返回Null
if(this.no == no){
return this;
}
if(this.left != null){
return this.left.preOrderSeacher(no);//进行遍历
}
if(this.right != null){
return this.right.preOrderSeacher(no);//向右遍历
}
return null;//无论找到没都需要返回了
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", left=" + left +
", right=" + right +
'}';
}
}
删除叶子二叉树节点
1.递归找到要删除节点的父亲节点
2.然后将左边或者右边那个要删除的节点直接值为null
3.记得上来先判断一把root节点,毕竟root节点本身有可能就那啥,root节点那啥的话直接值null
删除节点程序
package org.example.sort;
public class HeroNode {
public int no;
public String name;
public HeroNode left;
public HeroNode right;
public HeroNode(int no, String name, HeroNode left, HeroNode right) {
this.no = no;
this.name = name;
this.left = left;
this.right = right;
}
public HeroNode() {
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//这里一定要用this,因为每次动的都是不同的节点,每次this都不一样
public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
//前序遍历输出
System.out.print(this + " ");//输出自己然后向左
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
else if(this.right != null){
this.right.preOrder();
}
}
public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
System.out.print(this + " ");
if(this.right != null){
this.right.preOrder();
}
}
public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
if(this.left != null){
this.left.preOrder();//左指针调用方法进行递归
}
if(this.right != null){
this.right.preOrder();
}
System.out.print(this + " ");
}
//前序遍历查找某个节点
public HeroNode preOrderSeacher(int no){
//先比较一下当前节点是不是
//这里一定要用this,
//无论如何都要返回一个东西,所以需要一个resultNode,实在不行返回Null
if(this.no == no){
return this;
}
if(this.left != null){
return this.left.preOrderSeacher(no);//进行遍历
}
if(this.right != null){
return this.right.preOrderSeacher(no);//向右遍历
}
return null;//无论找到没都需要返回了
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", left=" + left +
", right=" + right +
'}';
}
//思路,用头节点判断左右节点是不是no,是的话直接为Null
//不是的话先左后右遍历
public void delNode(int no){
//删除某个节点
//这里已经直接进去二叉树了,头节点交给,顶上调用的方法进行判断
if(this.left.no == no && this.left != null){
this.left = null;
System.out.println("成功删除了");
}
else if(this.right.no == no && this.right != null){
this.right = null;
System.out.println("成功删除了");
}
else if(this.left != null){
this.left.delNode(no);//左边节点直接调用递归
}
else if(this.right != null){
this.right.delNode(no);
}
}
}
package org.example.sort;
public class BinaryTree {
private static HeroNode root;
public HeroNode getRoot() {
return root;
}
public void setRoot(HeroNode root) {
this.root = root;
}
public void preOrder(){
if(root != null){
this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void midOrder(){
if(root != null){
this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void backOrder(){
if(root != null){
this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void preOrderSeacher(int no){
//放进来一个数据
if(root != null){
HeroNode heroNode = root.preOrderSeacher( no);
if(heroNode == null){
System.out.println("没找到节点");
}
else
System.out.println(heroNode);
}
}
public void delSomeNode(int no){
int flag;
if(root.no == no){
root = null;
System.out.println("删除了");
return;
}
root.delNode(no);
}
}
顺序二叉树,
这就是顺序二叉树
区别无非就是左节点变成了
2n + 1 ,右节点变成 2n + 2
这种顺序二叉树遍历就是这样
前序遍历就是这么简单,没啥难度。
在原来递归基础上,变成了数组仅此而已
线索化说白了就是为下一次遍历指明线索,创造线索给你追寻。
说白了就是让空着的指针,发挥一些作用。
注意的点是,你的左指针有可能面对是前驱节点,也可能只是自己的左子树
你的右指针也能面对的是前驱节 点,或者右子树。
这个是参照,一开始8这个节点没有前驱节点,8的前驱节点是null
用左指针指向前驱节点,如果有的话,用右指针指向后继节点,如果有的话,指向之后,别忘了leftType和rightType两个标志位为1
pre指向前驱节点,node是当前节点
永远记住,pre.right = node设置后继节点,node.left = pre;//设置前驱节点
pre 指向 node用来设置前驱节点,node指向pre设置后继节点
package org.example.sort;
public class BinaryTree {
private static HeroNode root;
private HeroNode pre;//前驱节点,用来线索化,总是保留前一个节点
//二叉树线索化
public void threadNodes(HeroNode node){
//node代表当前需要线索化的节点
if(node == null){
return;
}
//中序遍历嘛,左中右
//先处理左子树
threadNodes(node.left);
//处理中间过程,先处理前驱节点,左指针代表前驱节点
//一个node如果左指针空着可以用来做前驱节点
if(node.left == null){
node.left = pre;//等于前驱节点
node.setLeftType(1);//同时说明自己左指针说明的是前驱结点
}
//一个pre如果右指针控制,可以用来指向后继节点
if(pre != null&&pre.right == null){
pre.right = node;
pre.setRightType(1);
}
pre = node;//pre要跟着一起进行移动,随着递归进行.pre也要跟着动
//处理右子树
threadNodes(node.getRight());
}
public HeroNode getRoot() {
return root;
}
public void setRoot(HeroNode root) {
this.root = root;
}
public void preOrder(){
if(root != null){
this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void midOrder(){
if(root != null){
this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void backOrder(){
if(root != null){
this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
}
}
public void preOrderSeacher(int no){
//放进来一个数据
if(root != null){
HeroNode heroNode = root.preOrderSeacher( no);
if(heroNode == null){
System.out.println("没找到节点");
}
else
System.out.println(heroNode);
}
}
public void delSomeNode(int no){
int flag;
if(root.no == no){
root = null;
System.out.println("删除了");
return;
}
root.delNode(no);
}
}
遍历线索化的二叉树,方法很简单,因为指针指向了线索化位置
可以不需要使用递归方式进行遍历,大大增加了效率,因为递归需要开辟新的站空间。
思路说白了就是,先找到最左边第一个被线索化的节点,然后从这个节点开始,将根据指引,将一个个节点都输出出来。
public void outthreadNodes(){
//遍历线索化之后的二叉树
HeroNode node = root;//从头节点开始,一直向左走,找到第一个leftType = 1的节点然后输出
while (node != null){
//使用循环进行遍历
while (node.getLeftType() == 0){
//一直往左找,找到一个有前驱节点的节点
node = node.getLeft();
}
//输出有前驱节点的点
System.out.print(node.no);
while(node.getRightType() == 1){
node = node.getRight();
System.out.println(node.no);//如果右后继节点,就输出后继节点,一直到没有后继节点
}
//没有后继节点的点,直接往右边走
node = node.getRight();
}
}
这是遍历线索化二叉树的代码
一进来一个节点,先往左找,一直找到第一个有前驱节点的点,然后输出这个节点
结束后,当前这个节点如果有后节点的指示
rightType = 1,就一直按照指示,往右指针走,一直走到指示没了,该自己摸石头过河了。,这时候,自己还是要往右走。
整个线索化时候,关键点就在于
leftType == 1时候面对的有前驱节点,righttype = 1是有后继节点。
中序遍历顺序
7,5,3,1,2,3,11,25
我们分析一下所有节点找一下规律
节点
1.有前驱节点,有后继节点
比如
7,9,2,25这几个节点,
直接往后走就行了
2.有前驱没有后继
11
说明往左走没戏,只能往右走,
3.有后继没有前驱
//这个不重要,有后继走后继就行了
4.前驱后继都没有
5,1,3
没有后继节点有两种情况
第一种,刚进循环就没有后继
根据代码,
我们每个节点一进到循环,就拼命往左走,一直找到一个有前驱的节点,输出这个节点,这个节点就是开始
倘若输出这个节点之后,这个节点有后继,那么就跟着后继走就行了,这个有前驱的节点如果没有后继,你想想,它也不可能往左走的,因为左边他妈的是前驱,你必须node = node.right,只能往右边走。
当你被别人的后继节点,一直推推推,推到一个没有前驱,没有后继的位置时候,比如
2-》3这个过程,实际上是从2 的后继节点,推到了3这个没有前驱,没有后继的位置,这时候也只能往右走,因为你是被2的右指针,推过来的,你倘若有左前驱节点,那就是你刚才被推过来那个2节点,你肯定不能往前驱节点走,你只能往右手边走。
向右进行搜索
知道了深度,我们就知道需要返回多少个树了,每层深度只能返回一个数
说白了,就是每一层元素,最右边那个展示出来就行
我们可以选择广度优先的遍历方式,将每一层元素中,最右边的那个放进linkedList里面
我们去遍历每一个元素,
每一层维持一个queque队列
上一层将所有节点放进队列中,从尾巴放进来
queue队列在做事,将下一层所有所有节点放进队列尾巴
本层做的是,每次进来前让queue不为零,不断将下面的节点放进来,然后同时让头部先进来节点出去,
但是我们要控制好每一层,需要记录当前层中节点个数,当当前层节点都出去了,说明进了下一层,
每一层做的事
1.将每个节点左右节点插进尾巴,
2.当i遍历到这一层最后一个节点时候,说明这就是最后一个节点了
最后一个节点就会这一层最右边的节点
那么只需要交给返回值就行了。
可以用一个for循环来控制把当前层都派出去。
似乎这种路径题目,都是递归
但是我们需要了解的东西是,递归每个节点在干吗,返给上层的东西是什么?如果不明白就很难做这个事情。