二叉排序树的构建、插入、删除以及二叉树的打印

来源:互联网 发布:花生壳用自己的域名 编辑:程序博客网 时间:2024/06/15 10:25
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">    定义:二叉排序树,也可以成为二叉查找树  它的性质如下:</span>
     * 1.若它的左子树不为空,则左子树上所有的节点均小于其根节点
     * 2.若它的右子树不为空,则右子树上所有的节点的值均大于根节点

     * 3.它的左右子树也分别为二叉排序树。       

     第一步  定义一个树的结点类

class node{int key;//结点的键    String value;//结点的值node lchild;node rchild;int size;//定义这个结点所在树的结点总数  即叶子节点size=1 非叶子节点size=lchild.size+rchild.size+1//带参数构造函数node(int key,String value,node lchild,node rchild){this.key=key;this.value=value;this.lchild=lchild;this.rchild=rchild;if(lchild==null&&rchild==null){size=1;}else{int lsize=0,rsize=0;if(lchild!=null){lsize=lchild.size;}if(rchild!=null){rsize=rchild.size;}size=lsize+rsize+1;}}//不带参数构造函数node(){}}
2 定义一个树结构

//定义一个树结构  其中nodes[0] 设置为根节点class tree{private ArrayList<node> nodes=new ArrayList<node>();//定义树的结点集合private int size;//定义树的节点总数private node root;//定义无参构造函数tree(){}//定义包含了根节点的构造函数tree(node root){this.root=root;}//定义结点的构造函数tree(ArrayList<node> nodes,node root){this.nodes=nodes;this.size=nodes.size();this.root=root;}}

3 定义二叉树的查找  根据key值进行查找,返回boolean值

//定义一个二叉树的查找 返回值是boolean类型的public static boolean get1(node root,int key,node pointer){//这个pointer对应的是一个指针  //当进行查找的时候,找到即指向找到的位置 找不到执行最后执行的位置pointer=root;if(pointer==null) System.out.println("你输入的是一个空树!");while(pointer!=null){if(pointer.key==key){//在这里将其进行直接赋值return true;}else if(pointer.key<key){  //在右子树中进行查找if(pointer.rchild==null) return false;else pointer=pointer.rchild;}else{//在左子树中查找if(pointer.lchild==null) return false;else pointer=pointer.lchild;}}return false;}
4 定义二叉树的插入节点

 //利用递归实现二叉树的插入操作public static void insert(node root,int key,String value){node pointer=root;if(pointer.key==key){pointer.value=value;}else if(pointer.key<key){//在右子树中进行查找if(pointer.rchild==null){node newNode=new BST().new node(key, value, null, null);pointer.rchild=newNode;myTree.size++;//在这里需要将这个结点放入myTree.nodes这个arraylist中myTree.nodes.add(newNode);System.out.println("增加了一个结点,当前结点数是"+myTree.size);}else{insert(root.rchild, key, value);}}else{if(pointer.lchild==null){node newNode=new BST().new node(key, value, null, null);pointer.lchild=newNode;myTree.size++;//在这里需要将这个结点放入myTree.nodes这个arraylist中myTree.nodes.add(newNode);System.out.println("增加了一个结点,当前结点数是"+myTree.size);}else                 insert(root.lchild, key, value);}}
5 定义二叉树的删除操作

//对二叉排序树进行删除操作  public static boolean delete(node root,int key){if(root==null) return false;else{if(root.key>key){return delete(root.lchild, key);//在左子树进行查询}else if(root.key<key)return delete(root.rchild, key);elsereturn del(root,key);//找到对应的结点,对其进行删除操作}}//对结点进行删除的操作  //对结点进行删除有三种情况  结点是叶子节点 结点只包含左子树或者右子树 结点包含左右子树//第一种直接删除 第二种子承父业  第三种选择其中序遍历的前驱或者后继结点(也就是与删除的结点key最接近的结点)//以找到前驱为例 删除操作就是  将前驱结点的node属性赋值到待删除的结点上  然后删除前驱结点 如果该前驱结点存在左子树,//(不可能存在右子树 如果存在右子树,表示存在比该前驱结点更大的小于待删除结点的结点)//分两种情况   该待删除结点左子树存在右子树 即指针会向右子树移动 此时讲该右子树的左子树连到右子树上//如果待删结点只存在左子树 前驱就是其左子树的根 此时就需要重接左子树public static boolean del(node root,int key){myTree.size--;node pointer=root;//该节点为指针结点node s=root;if(pointer.lchild==null&&pointer.rchild==null){pointer=null;}else if(pointer.lchild!=null&&pointer.rchild==null){//只存在左子树pointer=pointer.lchild;}else if(root.rchild!=null&&root.lchild==null){pointer=pointer.rchild;}else{//如果存在左右子树pointer=root.lchild;while(pointer.rchild!=null){s=pointer;//s这个指针比pointer少移了一步 意味着其是pointer的父节点pointer=pointer.rchild;//找到其前驱结点 即小于待删除结点的最大的点}//找到pointer的值之后将 pointer指向的结点的值赋给待删除结点root.key=pointer.key;root.value=pointer.value;//然后根据s是否右移判断待删除结点是否存在右子树if(s!=root){//右移 重接右子树s.rchild=pointer.lchild;}else{s.lchild=pointer.lchild;}}//在这里需要将树中的相应结点删除myTree.nodes.remove(pointer);for(int i=0;i<myTree.nodes.size();i++)System.out.println(myTree.nodes.get(i).value);System.out.println("当前节点数是"+myTree.size);return true;}

6 为验证二叉排序树的插入删除操作是否正确 将二叉树在控制台进行输出

借鉴的思想: 用两个队列盛放树的节点 利用两个队列的形式  树的根节点入队列A 

 步骤1 队列A中元素出队 且其孩子入队列B 

 步骤2 队列B中元素出队 且保证队列B中元素的孩子入队列A  

 重复步骤1,2直至队列A B 均为空

public static void printTree(){Queue<node> queueA=new LinkedList<BST.node>();Queue<node> queueB=new LinkedList<BST.node>();queueA.add(myTree.root);while(queueA.size()!=0||queueB.size()!=0){if(queueA.size()!=0){while(queueA.size()!=0){node temp=queueA.poll();System.out.print(temp.key+"("+temp.value+")"+"  ");if(temp.lchild!=null)queueB.add(temp.lchild);if(temp.rchild!=null)queueB.add(temp.rchild);}System.out.println();}if(queueB.size()!=0){while(queueB.size()!=0){node temp=queueB.poll();System.out.print(temp.key+"("+temp.value+")"+"  ");if(temp.lchild!=null)queueA.add(temp.lchild);if(temp.rchild!=null)queueA.add(temp.rchild);}System.out.println();}}}
7 对以上操作进行测试

public static void main(String[] args) {node D=new BST().new node(1, "D", null, null);//测试中将nodeshezhnode E=new BST().new node(4, "E", null, null);node B=new BST().new node(3, "B", D, E);node F=new BST().new node(7, "F", null, null);node C=new BST().new node(8, "C", F, null);node A=new BST().new node(5, "A", B, C);ArrayList<node> nodes=new ArrayList<BST.node>();nodes.add(D);nodes.add(E);nodes.add(B);nodes.add(F);nodes.add(C);nodes.add(A);myTree=new BST().new tree(nodes,A);//将该树打印出来printTree();//测试getNodeByKey函数if(getNodeByKey(myTree.root,3)){System.out.println("找到该索引");}else{System.out.println("未找到该值");}//测试插入操作insert(myTree.root, 10, "G");insert(myTree.root, 2, "H");               //测试删除操作delete(myTree.root, 3);<pre name="code" class="java">                 printTree();

8 以上是插入节点时已经设定好结点的左右孩子结点,还有一种情况是,输入一个数组,根据数组的值,构建二叉排序树

//根据数组元素构造二叉排序树  数组的length表示的是数组初始化时的长度 如果没有对其进行赋值的话设置为nullnode[] nodesArr=new node[10];//数组初始化的时候需要设置其大小或者直接进行赋值操作//设置一些数组,需要通过插入的形式 构造二叉树 nodesArr[0]=new BST().new node(6, "A", null, null);nodesArr[1]=new BST().new node(3, "B", null, null);nodesArr[2]=new BST().new node(9, "C", null, null);nodesArr[3]=new BST().new node(12, "D", null, null);nodesArr[4]=new BST().new node(15, "E", null, null);nodesArr[5]=new BST().new node(1, "F", null, null);nodesArr[6]=new BST().new node(7, "G", null, null);//通过数组构造一个二叉排序树 返回排序树的rootbuildTreeByArray(nodesArr);

//构造二叉树public static void buildTreeByArray(node[] arr){tree newTree =new BST().new tree(arr[0]);int i=1;while(arr[i]!=null){insert(newTree.root, arr[i].key, arr[i].value);i++;}}
9 增加一个微软的面试题 给定一个排序好得数组,将其转化成二叉排序树

思想:如果进行直接插入的化,树会变成极端的右斜树,深度变大的后果是导致查找需要更多的比较次数  所以如果给定的是一个有序的数组,可以将中间的数作为根root,将中

间数左边的数作为左子树,右边的树作为右子树

        int[] arr={1,2,3,4,5,6,7,8,9};
        tempNode root1=buildBSTBySortedArr(arr,0,arr.length-1);
       //根据排序数组构造二叉排序树 返回该二叉排序树的根节点public static tempNode buildBSTBySortedArr(int[] arr,int low,int high){if(low>high) return null;else{int mid=low+(high-low)/2;tempNode root=new tempNode(arr[mid]);if(low==high) return root;else{  //利用递归的手段进行查找root.lchild=buildBSTBySortedArr(arr, low, mid-1);root.rchild=buildBSTBySortedArr(arr, mid+1, high);}return root;//最后返回生成的二叉排序树的根节点,方便对该二叉排序树进一步操作(增、删、改、查,遍历等)}}

以上是复习二叉排序树的一点小小的总结,多多借鉴了别人的思想,如您发现疏漏或者错误,请批评指正,谢谢!
            






0 0