二叉树基本操作:
导语:你是否还在为不懂如何学好二叉树而发愁,是否还在纠结如何创建构造结点,如何将栈和队列巧妙的结合起来运行程序。徐小渣特对此做以归纳总结,希望能对大家有所帮助。
1.树结点的构造:
class BtNode {
public BtNode lchild;//左孩子结点
public BtNode rchild;//右孩子结点
public char data;//存储的数值
public BtNode(BtNode lchild,BtNode rchild){
this.lchild=lchild;
this.data=data;
}
public BtNode(char data){
this.data=data;
}
public BtNode(){}
}
2.二叉树的创建方法:
法一:无参构造,向程序中输入内容,此代码默认为输入字符
//二叉树的创建方法
public static BtNode CreateTree() {
//char item;
BtNode s = null;
Scanner scanner = new Scanner(System.in);
char item = scanner.next().charAt(0);
if (item != '#') {
//s.data=ite`m;
s = new BtNode(item);
s.lchild = CreateTree();
s.rchild = CreateTree();
}
return s;
}
法二:含有参数,参数为提供的字符串和下标
static class Int {
private int index;
public Int() {
index = 0;
}
public Int(int x) {
index = x;
}
int GetIndex() {
return index;
}
void ind() {
index += 1;
}
}
//利用字符串和下标创建树 注意此处不能用i++
public static BtNode creat(String s, Int i) {
// Queue<BtNode> queue= new Queue<>();
BtNode b = null;
//int in=i.GetIndex();
if (s.charAt(i.GetIndex()) != '#') {
b = new BtNode(s.charAt(i.GetIndex()));
i.ind();
b.lchild = creat(s, i);
i.ind();
b.rchild = creat(s, i);
}
return b;
}
3.利用递归输出先序,中序,后序:
//先序
public static void Preorder(BtNode node) {
if (node != null) {
System.out.println(node.data);
Preorder(node.lchild);
Preorder(node.rchild);
}
}
//中序遍历
public static void Inorder(BtNode node) {
if (node != null) {
Inorder(node.lchild);
System.out.println(node.data);
Inorder(node.rchild);
}
}
//后序
public static void lastorder(BtNode node) {
if (node != null) {
Preorder(node.lchild);
Inorder(node.rchild);
System.out.println(node.data);
}
}
4.利用非递归进行先中后序遍历:(后序相对复杂,小徐在此处采用的方法是设置标志位和栈)
//先序非递归 利用栈:先进后出
public static void NicePreOrder(BtNode tree){
if(tree==null)return;
Stack<BtNode> stack=new Stack<>();
stack.push(tree);
//栈的特征是先进先出,则先把树的右边的入栈后入左边
while(!stack.empty()){
BtNode btNode=stack.pop();
System.out.print(btNode.data+" ");
if(btNode.rchild!=null) stack.push(btNode.rchild);
if(btNode.lchild!=null) stack.push(btNode.lchild);
}
}
//中序非递归 法一
public static void NiceInOrder(BtNode tree){
if(tree==null)return ;
Stack<BtNode> stack=new Stack<>();
while(!stack.empty()||tree!=null){
while (tree!=null){
stack.push(tree);
tree=tree.lchild;
}
tree=stack.pop();
System.out.print(tree.data+" ");
tree=tree.rchild;
}
}
//中序非递归法二
public static void NiceInOrder2(StkNode tree){
Stack<StkNode> stack=new Stack<>();
if(tree ==null) return;
stack.push(tree);
while(!stack.empty()){
StkNode node=stack.pop();
if(++node.popnum==2){
System.out.print(node.ptr.data+" ");
if(node.ptr.rchild!=null){
stack.push(new StkNode(node.ptr.rchild));
}
}else{
stack.push(node);
if(node.popnum==1&&node.ptr.lchild!=null){
stack.push(new StkNode(node.ptr.lchild));
}
}
}
}
// 后序非递归法一
public static void NiceLOrder(BtNode tree){
Stack<BtNode> stack=new Stack<>();
//设置标志位,用来表示右孩子是否输出
BtNode flag=null;
while(!stack.empty()||tree!=null){
while(tree!=null){
stack.push(tree);
tree=tree.lchild;
}
//此时获取的元素为树最左边的根
tree=stack.pop();
//判断其是否有右子树,或者右子树是否被输出过
//表示无右子树或者已被输出过
if(tree.rchild==null||tree.rchild==flag){
System.out.print(tree.data+" ");
flag=tree;//把标志位转移到tree的位置
tree=null;
}
else{stack.push(tree);
tree=tree.rchild;
}
}
}
```java
//法二: 后序非递归
static class StkNode{
public BtNode ptr=null;
public int popnum=0;
public StkNode(BtNode p){ptr=p;popnum=0;}
}
public static void NiceLOrder2(StkNode tree){
Stack<StkNode> stack=new Stack<>();
if(tree ==null) return;
stack.push(tree);
while(!stack.empty()){
StkNode node=stack.pop();
if(++node.popnum==3){
System.out.print(node.ptr.data+" ");
}else{
stack.push(node);
if(node.popnum==1&&node.ptr.lchild!=null){
stack.push(new StkNode(node.ptr.lchild));
}
else if(node.popnum==2&&node.ptr.rchild!=null){
stack.push(new StkNode(node.ptr.rchild));
}
}
}
}
**5.层序遍历:**
```java
//层序遍历 队的特点:先进先出
public static void NiceLevelOrder(BtNode tree){
Queue<BtNode> queue=new LinkedList<>();
queue.offer(tree);
while(!queue.isEmpty()){
tree=queue.poll();
System.out.print(tree.data+" ");
//先入左边后入右边
if(tree.lchild!=null)queue.offer(tree.lchild);
if(tree.rchild!=null)queue.offer(tree.rchild);
}
}
6-7.已知先序和中序的输出结果,求原始二叉树:
(思路与下文七思路一致,有递归思想)
以该题为例:分析先序和中序的特点,先序的输出的第一个即为树的根,在中序的输出结果找到和他一致的元素,返回该下标,则以中序来说,可将其输出结果分为两部分,左边为根节点的左子树,右边为根节点的右子树,先序同理,找到上文提到的下标,则左子树为从根节点的下一个开始到该下标的元素,右节点为剩下所有的元素。在进行划分,利用递归思想即可解题。
查找下标代码:
/先查找对应的下标
private static int search(String s,char value){
int pos=-1;
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i)==value) {pos=i;break;}
}
return pos;
}
已知先序和中序的输出结果,求原始二叉树
// pstr 先序排列的字符串 istr的字符串 n所含元素个数
private static BtNode CreatPI(String pstr, String istr, int n) {
if(pstr!=null&&istr!=null) {
BtNode s = new BtNode(pstr.charAt(0));;
if (n > 0) {
int pos = search(istr, s.data);
if(pos==-1)return null;
s.lchild = CreatPI(pstr.substring(1, pos + 1), istr.substring(0, pos), n);
s.rchild = CreatPI(pstr.substring(pos + 1), istr.substring(pos + 1), n - pos - 1);
}
return s;
}
return null;
}
已知中序和后序的输出结果,求原始二叉树
//已知中序 后序 求原始二叉树
private static BtNode CreatIL(String istr,String lstr,int n) {
if (istr != null && lstr != null) {
BtNode s = null;
if (n > 0) {
s = new BtNode(lstr.charAt(lstr.length() - 1));
int pos = search(istr, lstr.charAt(lstr.length() - 1));
if(pos==-1)return null;
s.lchild = CreatIL(istr.substring(0, pos), lstr.substring(0, pos), pos);
s.rchild = CreatIL(istr.substring(pos + 1), lstr.substring(pos, n - 1), n - pos - 1);
}
return s;
}
return null;
}
写出k行的全部数值
public static void Printk(BtNode ptr,int k){
if(ptr==null||k<0)return;
if(ptr!=null&&k==0){
System.out.print(ptr.data+" ");
}
else if(ptr!=null){
Printk(ptr.lchild,k-1);
Printk(ptr.rchild,k-1);
}
}
获取节点个数 分治策略思想
//获取节点个数 分治策略思想
public static int Getsize(BtNode tree){
if(tree==null) return 0;
else return Getsize(tree.lchild)+Getsize(tree.rchild)+1;
}
获取深度
//获取深度
public static int GetDepth(BtNode tree){
if(tree==null) return 0;
else return Math.max(GetDepth(tree.lchild),GetDepth(tree.rchild))+1;
}
在树中查找某值是否存在
//在树中查找某值是否存在
public static boolean FindValue(BtNode tree,char c){
if(tree==null) return false;
boolean flag=false;
if(tree.data==c) return true;
else {
if(tree.lchild!=null) flag=FindValue(tree.lchild,c);
else if(tree.rchild!=null) flag=FindValue(tree.rchild,c);
}
return flag;
}
获取双亲节点
//获取双亲
public static BtNode GetParent(BtNode tree,BtNode child) {
if (child == null || tree == null || tree == child) return null;
if ((tree.lchild != null && tree.lchild == child) || (tree.rchild != null && tree.rchild == child)) {
return tree;
} else if (tree.lchild != null) {
tree = GetParent(tree.lchild, child);
if (tree == null) {
tree = GetParent(tree.rchild, child);
}
}
return tree;
}
判断是否是满二叉树 要么树为空 要么树的左子树为满同时树的右子树为满且两者高度相同
//判断是否是满二叉树 要么树为空 要么树的左子树为满同时树的右子树为满且两者高度相同
public boolean IsFull(BtNode p){
return (p==null||(IsFull(p.lchild)&&IsFull(p.rchild)&&(GetDepth(p.lchild)==(GetDepth(p.rchild)))));
}
判断是否是满二叉树
//判断是否是满二叉树
public boolean Is_Full(BtNode tree){
Queue<BtNode> queue=new LinkedList<>();
int n=1;
boolean res=true;
if(tree==null) return res;
queue.offer(tree);
while(!queue.isEmpty()){
if(queue.size()<n){
res=false;
break;
}
for (int i = 0; i < n; i++) {
BtNode p=queue.poll();
if(p.lchild!=null){
queue.offer(p.lchild);
}
if(p.rchild!=null){
queue.offer(p.rchild);
}
}
n+=n;
}
return res;
}
判断是否是完全二叉树
// 判断是否是完全二叉树
public static boolean Is_ComTree(BtNode tree) {
boolean res = true;
if (tree == null) return res;
Queue<BtNode> queue = new LinkedList<>();
queue.offer(tree);
while (!queue.isEmpty()) {
tree = queue.poll();
if (tree == null) break;
queue.offer(tree.lchild);
queue.offer(tree.rchild);
}
while (!queue.isEmpty()) {
tree = queue.poll();
if (tree != null) {
res = false;
break;
}
}
return res;
}
对数组进行中序操作 递归操作
//对数组进行中序操作 递归操作
public static void Inorder_arr(int[] arr,int i,int end){
if(i<=end&&arr[i]!=-1){
Inorder_arr(arr,2*i+1,end);
System.out.print(arr[i]+" ");
Inorder_arr(arr,2*i+2,end);
}
}
非递归操作
//非递归操作
public static void NiceInorder_arr(int[] arr){
if(arr.length<=0)return;
Stack<Integer> stack=new Stack<>();
int i=0,end=arr.length-1;
while((i<=end&&arr[i]!=-1)||!stack.empty()){
while(i<=end&&arr[i]!=-1){
stack.push(i);
i=i*2+1;
}
i=stack.pop();
System.out.print(arr[i]+" ");
i=2*i+2;
}
}
链式存储二叉树 将数组转换成链表的形式
public static BtNode CreatAr(int[] arr,int index){
BtNode tree=null;
if(index<arr.length-1&&arr[index]!=-1) {
tree = new BtNode(arr[index]);
tree.lchild=CreatAr(arr,index+1);
tree.rchild=CreatAr(arr,index+1);
}
return tree;
}
将中序遍历转换为双向链表
// 将中序遍历转换为双向链表
public static void inoder(BtNode tree) {
BtNode pre=null;
BtNode ptr=tree;
if (tree == null) return;
Stack<BtNode> stack = new Stack<>();
while (!stack.empty()||ptr!=null) {
while (ptr != null) {
stack.push(ptr);
ptr=ptr.lchild;
}
ptr = stack.pop();
if(pre==null){
pre=ptr;
tree=ptr;
}
else {
pre.rchild=ptr;
ptr.lchild=pre;
pre=ptr;
}
ptr=ptr.rchild;
}
}
主函数调用:
public static void main(String[] args) {
Int i=new Int(0);
BtNode node= creat("abc####",i);
// System.out.print(node.data);
// BtNode x=CreateTree();
// Preorder(node);
//lastorder(node);
BtNode node1=new BtNode();
// String pstr="abdecfg";
String istr="dbeafcg";
String lstr="debfgca";
//String istr="badc";
//String lstr="bdca";
node1=CreatIL(istr,lstr,7);
// Preorder(node1);
// NiceInOrder(node1);
//NiceLOrder1(node1);
//NiceLevelOrder(node1);
StkNode node2=new StkNode(node1);
// NiceLOrder2(node2);
// NiceInOrder2(node2);
// Printk(node1,2);
// System.out.println(Getsize(node1));
//System.out.println(GetDepth(node1));
//System.out.println(FindValue(node1,'u'));
System.out.println(Is_ComTree(node1));
int[] arr={31,23,12,66,-1,5,17,70,62,-1,-1,88,-1,55};
Inorder_arr(arr,0,arr.length-1);
// inoder(node1);
NiceInorder_arr(arr);
}
}