java二叉树之堆

xiaoxiao2021-02-28  37

堆是完全二叉树的分布逻辑,结构可以用数组或树等实现。在完全二叉树的基础上,加上父节点优先级始终大于子节点优先级的规则,是一种弱序结构。

堆一般用于优先级存储结构,插入和删除根节点比较方便,但是查找、顺序遍历和删除其他关键字节点就不爽了。

堆排序是一种与快排复杂度相同O(NlogN)的排序,效率略低于快排,但是它很稳定,不受数据分布影响,而快排最差效率可降低到O(N*N)。

1,基于数组的堆import java.util.Random;class Item {    int data;    public Item(int data) {        this.data = data;    }}public class Heap {    private Item[] array;    private int maxSize;    private int curSize;    public Heap(int size) {        maxSize = size;        curSize = 0;        array = new Item[size];    }    public boolean insert(int key) {        if (curSize == maxSize)            return false;        array[curSize] = new Item(key);        trickleUp(curSize++);        return true;    }    private void trickleUp(int index) {        Item bottom = array[index];// 把这个要插入的先提出来        int parent = (index - 1) / 2;// 父节点索引        while (index > 0 && array[parent].data < bottom.data) {            array[index] = array[parent];// 父节点下移            index = parent;            parent = (parent - 1) / 2;        }        array[index] = bottom;    }    public Item remove() {        Item root = array[0];        array[0] = array[--curSize];        trickleDown(0);        return root;    }    private void trickleDown(int index) {        Item top = array[index];        int large;        while (index < curSize / 2) {// 此时至少一个子节点            int left = 2 * index + 1;            int right = left + 1;            // 包含了有无右节点2种情况            if (right < curSize && array[right].data > array[left].data)                large = right;            else                large = left;            if (top.data >= array[large].data)                break;            array[index] = array[large];            index = large;        }        array[index] = top;    }//改变节点优先级    public boolean change(int index, int newValue) {        if (index < 0 || index >= curSize)            return false;        int oldData = array[index].data;        if (newValue > oldData)            trickleUp(index);        else            trickleDown(index);        return true;    }//逐层显示,格式没调的好看    public void display() {        int n = 1;        while (true) {            for (int i = n - 1; i < 2 * n - 1; i++) {                if (i >= curSize) {                    System.out.println("\n---------------------------------");                    return;                }                System.out.print(array[i].data + " ");            }            System.out.println();            n *= 2;        }

    }

//堆排序

public void sort(Item[] beforeSort){        array=beforeSort;        maxSize=curSize=beforeSort.length;        for(int i=0;i<maxSize;i++)            System.out.print(array[i].data+"/");        System.out.println();        //对含有子节点的节点向下调整,一直调整到根,就将无序数组转换成了堆        for(int j=maxSize/2-1;j>=0;j--)            trickleDown(j);        //每次将最高优先级的数据按从数组末端到数组开头的顺序放进去,这样排序不需要第二个数组,直接将无序数组转变成有序数组        for(int k=maxSize-1;k>0;k--){            array[k]=remove();

        }

//排序后输出

        for(int i=0;i<maxSize;i++)            System.out.print(array[i].data+"/");        System.out.println();    }    public static void main(String[] args) {        Heap heap = new Heap(31);        Random rand = new Random();        for (int i = 0; i < 20; i++)            heap.insert(rand.nextInt(100));        heap.display();        heap.remove();        heap.display();    }}

2,使用树构建堆,称为树堆import java.util.ArrayList;import java.util.List;import java.util.Random;//问题在于找到树的最后一个节点的位置(插入及删除)class Node {    Node parent;    Node left;    Node right;    int data;    public Node(int data) {        this.data = data;        parent = null;        left = null;        right = null;    }}class TreeHeap {    Node root;    int size;    public TreeHeap() {        root = null;        size = 0;    }    public void insert(int key) {        Node current = root;

        Node temp = null;

        //得到要插入位置的信息(逆序的):如要插入位置为1011,表示从根节点到插入位置是右左右右的方向

        List<Integer> list = sizeToCode(++size);

    //从list倒数第二个开始遍历到首个,就是位置的信息

        for (int i = list.size() - 2; i >= 0; i--) {            temp = current;            if (list.remove(i) == 1)//1就向右,0向左                current = current.right;            else                current = current.left;        }        if (current == root)//第一次插入            root = new Node(key);        else {            current = new Node(key);            current.parent = temp;            if (size % 2 == 0)                temp.left = current;            else                temp.right = current;            thickleUp(current);//跟第一种方法类似的调整        }    }    // 改变节点数据即可    private void thickleUp(Node node) {        Node temp = node;        while (node != root) {            if (temp.data > node.parent.data) {                node.data = node.parent.data;                node = node.parent;            } else                break;        }        node.data = temp.data;    }    public Node remove() {        if (size == 0)            return null;        Node temp = root;        Node current = root;        List<Integer> list = sizeToCode(size);        for (int i = list.size() - 2; i >= 0; i--) {            if (list.remove(i) == 1)                current = current.right;            else                current = current.left;        }        if (current == root) {// size=1            root = null;            size--;        } else {            root.data = current.data;            current = null;            size--;            thickleDown(root);        }        return temp;    }    private void thickleDown(Node node) {        int key = node.data;        Node large;

        while (node != null) {

            if (node.left != null && node.right != null) {                if (node.left.data > node.right.data)                    large = node.left;                else                    large = node.right;                if (key >= large.data)                    break;                else {                    node.data = large.data;                    node = large;                }            } else if (node.left != null) {                if (key >= node.left.data)                    break;                else {                    node.data = node.left.data;                    node = node.left;                }            } else if (node.right != null) {                if (key >= node.right.data)                    break;                else {                    node.data = node.right.data;                    node = node.right;                }            } else                break;        }        node.data = key;    }    // 找出最后一个节点所处位置,通过树的大小,将其转换成二进制编码,    // 如第5个节点,5对应二进制101,去掉开头的1,即左右即是它的位置    // 此时返回的是逆序的,遍历的时候倒过来即可    public List<Integer> sizeToCode(int size) {        List<Integer> list = new ArrayList<Integer>();        while (size >= 1) {            list.add(size % 2);            size = size / 2;        }        return list;    }    public static void main(String[] args) {        TreeHeap heap = new TreeHeap();        Random rand = new Random(137);        int[] array = new int[20];        for (int i = 0; i < 20; i++) {            array[i] = rand.nextInt(1000);        }        for (int a : array)            heap.insert(a);        while (heap.size > 0) {            System.out.print(heap.remove().data + "/");        }    }}

转载请注明原文地址: https://www.6miu.com/read-2625552.html

最新回复(0)