二叉树的链式实现

↘锁芯ラ 提交于 2019-12-21 07:21:22


相关术语:

平衡树,非平衡树,完全数,满树。

实现策略:

1)数组实现

这个还是非常重要的,有时间写一下,先用链来写

元素n的(从0开始按层编号)左子树编号为2n+1,右子树编号为2n+2,数学证明就略了,用这个来控制下标

2)模拟链式实现

3)链式实现


树是一种非线性结构,那么跟前不一样,必须根据你的需求来构造新的节点才能满足树中的节点特征

package Tree;public class BinaryTreeNode {    protected Object element;    protected BinaryTreeNode left,right;            public BinaryTreeNode(Object element)//用元素来构造一个结点    {        this.element = element;        left = null;        right = null;    }        public int numChildren(){//返回结点的子树上结点的个数                int count = 0;        if(left != null)            count = 1 + left.numChildren();        if(right != null)            count = count + 1 + right.numChildren();        return count;    }    }


下面是一个实现了一些基本操作的二叉树的ADT:主要是三种遍历方式

BinaryTreeADT
package Tree;import java.util.Iterator;//引入迭代器后,对于遍历就直接将遍历的方法写在了迭代器中public interface BinaryTreeADT {    public int size();        public boolean isEmpty();        public boolean contains(Object element);        public void removeLeftSubtree();//删除左子树        public void removeRightSubtree();//删除右子树        public Object find(Object targetelement);//找到某个元素并返回其引用        public String toString();//返回树的字符串表示        public Iterator iteratorInorder();//返回中序遍历的迭代器        public Iterator PreInorder();//返回前序遍历的迭代器        public Iterator PostInorder();//返回后序遍历的迭代器        //public Iterator LevelInorder();//返回层次遍历的迭代器    }



下面来实现:

维护一个根节点和count变量来记录总共的节点数,以及下面的构造方法:

private int count;    protected BinaryTreeNode root;        //3个构造方法        public BinaryTree()    {        root = null;        count = 0;    }        public BinaryTree(Object element)    {        root = new BinaryTreeNode(element);        count = 1;    }        public BinaryTree(Object element,BinaryTree leftSubtree,BinaryTree rightSubtree)    {        root = new BinaryTreeNode(element);        count = 1;        if(leftSubtree != null)        {            count = count + leftSubtree.size();            root.left = leftSubtree.root;        }        else root.left = null;                if(rightSubtree != null)        {            count = count + rightSubtree.size();            root.right = rightSubtree.root;        }        else root.right = null;    }        



主要来看一下遍历的实现,把遍历写成一个迭代器(在链表里写了很多代码,感觉很憋屈,很多地方都花在遍历和迭代上,就是因为没有去实现Iterator)


在遍历中,要用到队列,先来看下队列迭代器是怎么实现的:

在前面写的队列LinkedQueue中,添加一个返回值为Iterator的方法:

public Iterator iterator(){        return new LinkedQueueIterator(front,rear,count);    }


它实际上是返回另一个继承了Iterator类的类的对象,这个对象的构造函数一般来说是由LinkedQueue里的成员变量组成的(因为要实现Iterator里面的方法):

package Queue;import java.util.Iterator;import Bag.LinearNode;public class LinkedQueueIterator implements Iterator {    private LinearNode front,rear,current;    private int count;        //迭代器类的构造器    public LinkedQueueIterator(LinearNode front,LinearNode rear,int count)    {        this.front = front;        this.rear = rear;        this.count = count;        this.current = front;    }            public boolean hasNext() {                return (current != null);    }    public Object next() {        Object result = current.getElement();        current = current.getNext();        return result;    }    public void remove() {            }}


上面说明了怎么去实现一个数据结构的迭代器,关键在于去实现特定于自身数据结构的Iterator方法(hasNext,next,remove)

在树的遍历中,需要借助于队列的迭代器,来返回一个树的迭代器,将树中元素按照遍历规则入队,最后返回队列的迭代器,这个迭代器就是树的迭代器。


中序遍历迭代器的实现(前序后序类似):借助于一个private的支持方法来将树中元素按序进队:

public Iterator iteratorInorder() {                LinkedQueue queue = new LinkedQueue();        inorder(root,queue);//将以root为根的树按序进队        return queue.iterator();//返回队列的迭代器    }        private void inorder(BinaryTreeNode node,LinkedQueue queue){        if(node != null)        {            inorder(node.left,queue);            queue.enqueue(node.element);            inorder(node.right,queue);        }    }


将遍历写成迭代迭代器会有利于很多后序操作,当然,也可以直接写一个遍历输出元素:

//直接写一个遍历的方法,不用迭代器也行    //public static void previsit(BinaryTreeNode node){        //if(node != null)        //{            //System.out.println(node.element);            //previsit(node.left);            //previsit(node.right);        //}                //}


其他操作参见注释,不再分析实现,清单代码:

BinaryTree
package Tree;import java.util.Iterator;import Queue.LinkedQueue;public class BinaryTree implements BinaryTreeADT {        private int count;    protected BinaryTreeNode root;        //3个构造方法        public BinaryTree()    {        root = null;        count = 0;    }        public BinaryTree(Object element)    {        root = new BinaryTreeNode(element);        count = 1;    }        public BinaryTree(Object element,BinaryTree leftSubtree,BinaryTree rightSubtree)    {        root = new BinaryTreeNode(element);        count = 1;        if(leftSubtree != null)        {            count = count + leftSubtree.size();            root.left = leftSubtree.root;        }        else root.left = null;                if(rightSubtree != null)        {            count = count + rightSubtree.size();            root.right = rightSubtree.root;        }        else root.right = null;    }                //接口定义的操作        public int size() {        return count;    }        public boolean isEmpty() {        return (count == 0);    }    public void removeLeftSubtree() {        if(root.left != null)            count = count - 1 - root.left.numChildren();        root.left = null;    }    public void removeRightSubtree() {        if(root.right != null)            count = count - 1 - root.right.numChildren();        root.right = null;    }        public Object find(Object target) {        Iterator it = this.iteratorInorder();        Object result = null;                while(it.hasNext())        {            result = it.next();            if(result.equals(target))                break;            else result = null;        }            return result;    }            public boolean contains(Object element) {        if(find(element) != null)            return true;        return false;    }        public Iterator iteratorInorder() {                LinkedQueue queue = new LinkedQueue();        inorder(root,queue);//将以root为根的树按序进队        return queue.iterator();//返回队列的迭代器    }        private void inorder(BinaryTreeNode node,LinkedQueue queue){        if(node != null)        {            inorder(node.left,queue);            queue.enqueue(node.element);            inorder(node.right,queue);        }    }        public Iterator PreInorder() {        LinkedQueue queue = new LinkedQueue();        preorder(root,queue);        return queue.iterator();    }        private void preorder(BinaryTreeNode node,LinkedQueue queue){        if(node != null)        {            queue.enqueue(node.element);            preorder(node.left,queue);            preorder(node.right,queue);        }    }        public Iterator PostInorder() {        LinkedQueue queue = new LinkedQueue();        postorder(root,queue);        return queue.iterator();    }    private void postorder(BinaryTreeNode node,LinkedQueue queue){        if(node != null)        {            postorder(node.left,queue);            postorder(node.right,queue);            queue.enqueue(node.element);        }    }        //直接写一个遍历的方法,不用迭代器也行    //public static void previsit(BinaryTreeNode node){        //if(node != null)        //{            //System.out.println(node.element);            //previsit(node.left);            //previsit(node.right);        //}                //}        public static void main(String[] args) {                BinaryTree  tree3 = new BinaryTree (3);        BinaryTree  tree4 = new BinaryTree (4);        BinaryTree tree2 = new BinaryTree(2,tree3,tree4);                BinaryTree  tree7 = new BinaryTree (7);        BinaryTree  tree6 = new BinaryTree (6,tree7,null);                BinaryTree  tree5 = new BinaryTree (5,null,tree6);                BinaryTree  tree1 = new BinaryTree (1,tree2,tree5);                System.out.println("树的大小是: " + tree1.size());        System.out.println("树为空吗?: " + tree1.isEmpty());                //previsit(tree1.root);                System.out.println("\n中序遍历结果为: ");        Iterator it = tree1.iteratorInorder();        while(it.hasNext())            System.out.print(it.next() + " ");                System.out.println("\n前序遍历结果为: ");        it = tree1.PreInorder();        while(it.hasNext())            System.out.print(it.next() + " ");                System.out.println("\n后序遍历结果为: ");        it = tree1.PostInorder();        while(it.hasNext())            System.out.print(it.next() + " ");                System.out.println("\n\n" + tree1.find(0));        System.out.println("包含元素6吗?: " + tree1.contains(6));        System.out.println("包含元素8吗?: " + tree1.contains(8));                            tree1.removeLeftSubtree();        System.out.println("\n删除左子树后中序遍历结果为: ");        it = tree1.iteratorInorder();        while(it.hasNext())            System.out.print(it.next() + " ");            }}



你会发现,并没有去实现add和delete操作,因为在具体的应用需求之前,并不知道该怎么去添加和删除,它不像线性结构,添加和删除后是要调整树的形状的。

由于没有写一个addleft,addright方法,构造一个树来测试显得很冗长,在main方法前面好多行,构造了下面的二叉树:




结果如下:


树的大小是: 7
树为空吗?: false

中序遍历结果为:
3 2 4 1 5 7 6
前序遍历结果为:
1 2 3 4 5 6 7
后序遍历结果为:
3 4 2 7 6 5 1

null
包含元素6吗?: true
包含元素8吗?: false

删除左子树后中序遍历结果为:
1 5 7 6



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!