数据结构实现之有序符号表BST二叉查找树

API

方法说明运行时间增长数量级
void put(Key key,Value val)将键值对存入表中(若值为空则将键key从表中删除)logN,最坏N
Value get(Key key)获取键key对应的值(若键key不存在则返回null)logN,最坏N
void delete(Key key)从表中删去键key(及其对应的值)logN,最坏N
boolean contains(Key key)键key在表中是否有对应的值logN
boolean isEmpty()表是否为空1
int size()表中的键值对数量1
Iterable keys()表中的所有键的集合
Key min()最小的键logN,最坏N
Key max()最大的键logN,最坏N
Key floor(Key key)小于等于key的键的数量logN,最坏N
Key ceiling(Key key)大于等于key的键的数量logN,最坏N
int rank(Key key)等于key的键的数量logN,最坏N
Key select(int i)排位为i的键logN,最坏N
void deleteMin()删除最小的键logN,最坏N
void deleteMax()删除最大的键logN,最坏N
int size(Key lo,Key hi)[lo,hi]之间键的数量1
Iterable keys(Key lo,Key hi)[lo,hi]之间所有的键,已排序
Iterable keys()有序表中所有的键,已排序

代码主要看put,get,delete,deleteMin,deleteMax,rank,select,floor,ceiling

package xwq.dt;

import xwq.util.StdIn;
import xwq.util.StdOut;

public class BST<Key extends Comparable<Key>, Value> {
    private Node root; // 二叉排序树根节点

    // 二叉树结点定义
    private class Node {
        public Key key;
        public Value val;
        public Node lchild;
        public Node rchild;
        public int N;// 结点数量,左子树结点数量+右子树结点数量+自身
        // 构造函数

        public Node(Key key, Value val, int n) {
            this.key = key;
            this.val = val;
            lchild = null;
            rchild = null;
            N = n;
        }
    }

    public BST() {
        root = null;
    }

    public boolean contains(Key key) {
        if (key == null)
            throw new NullPointerException();
        return get(key) != null;
    }

    public void put(Key key, Value val) {
        if (key == null)
            throw new NullPointerException();
        if (val == null)
            delete(key);
        root = put(root, key, val);
    }

    private Node put(Node root, Key key, Value val) {
        // 插入新结点
        if (root == null) {
            Node newnode = new Node(key, val, 1);
            return newnode;
        }

        // 查找key-value对,插入或更新位置
        int cmp = key.compareTo(root.key);
        if (cmp == 0)
            root.val = val;
        else if (cmp < 0)
            root.lchild = put(root.lchild, key, val);
        else
            root.rchild = put(root.rchild, key, val);

        // 子结点数量更新
        root.N = size(root.lchild) + size(root.rchild) + 1;
        return root;
    }

    public Value get(Key key) {
        if (key == null)
            throw new NullPointerException();
        return get(root, key);
    }

    private Value get(Node root, Key key) {
        if (root == null)
            return null;
        int cmp = key.compareTo(root.key);
        if (cmp == 0)
            return root.val;
        if (cmp < 0)
            return get(root.lchild, key);
        else
            return get(root.rchild, key);
    }

    public void delete(Key key) {
        if (key == null)
            throw new NullPointerException();
        if (!contains(key))
            return;
        root = delete(root, key);
    }

    private Node delete(Node x, Key key) {
        if (x == null)
            return null;
        int cmp = key.compareTo(x.key);
        if (cmp < 0)
            x.lchild = delete(x.lchild, key);
        else if (cmp > 0)
            x.rchild = delete(x.rchild, key);
        else {
            if (x.lchild == null)
                return x.rchild;// 被删除结点只有右子树
            if (x.rchild == null)
                return x.lchild;// 被删除结点只有左子树
            // 右子树最小替换到被删除结点位置
            // 1.将指向即将被删除的结点的链接保存为t
            // 2.将x指向它的后继结点min(t.right)
            // 3.将x的右链接(原本指向一颗所有结点都大于x.key的二叉查找树)指向deleteMin(t.right),
            // 也就是再删除后所有结点仍然都大于x.key的二叉查找树
            // 4.将x的左链接(本为空)设为t.left(其下所有的key都小于被删除结点和它的后继结点)
            Node t = x;
            x = min(t.rchild);
            x.rchild = deleteMin(t.rchild);
            x.lchild = t.lchild;
        }
        x.N = size(x.lchild) + size(x.rchild) + 1;
        return x;
    }

    private Node deleteMin(Node x) {
        if (x == null)
            return null;
        // 不断深入根节点的左子树,直至遇到一个空链接,然后指向该结点的链接指向该结点的右子树
        if (x.lchild == null)
            return x.rchild;
        x.lchild = deleteMin(x.lchild);
        x.N = size(x.lchild) + size(x.rchild) + 1;
        return x;
    }

    private Node deleteMax(Node x) {
        if (x == null)
            return null;
        // 不断深入根节点的右子树,直至遇到一个空链接,然后指向该结点的链接指向该结点的左子树
        if (x.rchild == null)
            return x.lchild;
        x.rchild = deleteMax(x.rchild);
        x.N = size(x.lchild) + size(x.rchild) + 1;
        return x;
    }

    // 0到N-1
    public int rank(Key key) {
        if (key == null)
            throw new NullPointerException();
        return rank(root, key);
    }

    // 0到N-1
    private int rank(Node root, Key key) {
        if (root == null)
            return 0;
        int cmp = key.compareTo(root.key);

        if (cmp < 0)
            return rank(root.lchild, key);
        else if (cmp > 0)
            return size(root.lchild) + 1 + rank(root.rchild, key);
        else
            return size(root.lchild);
    }

    // 0到N-1
    public Key select(int k) {
        if (k < 0 || k >= size())
            return null;
        return select(root, k);
    }

    // 0到N-1
    public Key select(Node root, int k) {
        int i = size(root.lchild);
        if (i > k)
            return select(root.lchild, k);// 存在于左子树
        else if (i < k)
            return select(root.rchild, k - i - 1);// 存在于右子树
        else
            return root.key;
    }

    public Key floor(Key key) {
        if (key == null)
            throw new NullPointerException();
        return floor(root, key);
    }

    private Key floor(Node root, Key key) {
        if (root == null)
            return null;

        int cmp = key.compareTo(root.key);

        // 存在相同的key
        if (cmp == 0)
            return root.key;
        // 如果待查找key < root.key,到root的左子树继续查找小于等于key的键
        if (cmp < 0)
            return floor(root.lchild, key);

        // 待查找key > root.key
        // 如果右子树已空,或右子树最小值大于key,那么root为最大下界结点
        Node rmin = min(root.rchild);
        if (rmin == null || key.compareTo(rmin.key) < 0)
            return root.key;
        // 不空,最大下界结点存在于右子树,继续到右子树需找
        return floor(root.rchild, key);
    }

    public Key ceiling(Key key) {
        if (key == null)
            throw new NullPointerException();
        return ceiling(root, key);
    }

    // 大于等于key的键
    private Key ceiling(Node root, Key key) {
        if (root == null)
            return null;

        int cmp = key.compareTo(root.key);

        if (cmp == 0)
            return root.key;
        // key > root.key,到右子树继续寻找符合条件的结点
        if (cmp > 0)
            return ceiling(root.rchild, key);

        // root.key > key,并且root左子树的都小于key,说明root是最小上界结点
        Node lmax = max(root.lchild);
        if (lmax == null || key.compareTo(lmax.key) > 0)
            return root.key;
        // 否则上界最小结点存在于左子树中,到左子树中寻找
        return ceiling(root.lchild, key);
    }

    public boolean isEmpty() {
        return root == null;
    }

    public int size() {
        return size(root);
    }

    private int size(Node p) {
        if (p == null)
            return 0;
        return p.N;
    }

    public Iterable<Key> levelOrder() {
        Queue<Key> keys = new Queue<Key>();
        if (root == null)
            return keys;

        // 使用队列做为辅助数据结构实现层次遍历
        Queue<Node> q = new Queue<Node>();
        q.enqueue(root);

        while (!q.isEmpty()) {
            Node node = q.dequeue();
            keys.enqueue(node.key);
            if (node.lchild != null)
                q.enqueue(node.lchild);
            if (node.rchild != null)
                q.enqueue(node.rchild);
        }

        return keys;
    }

    public Iterable<Key> keys() {
        return keys(min(), max());
    }

    public Iterable<Key> keys(Key lo, Key hi) {
        Queue<Key> queue = new Queue<Key>();
        keys(root, queue, lo, hi);
        return queue;
    }

    private void keys(Node x, Queue<Key> queue, Key lo, Key hi) {
        if (x == null || lo == null || hi == null)
            return;
        int cmp1 = lo.compareTo(x.key);
        int cmp2 = hi.compareTo(x.key);
        // 中序遍历
        if (cmp1 < 0)
            keys(x.lchild, queue, lo, hi);
        if (cmp1 <= 0 && cmp2 >= 0)
            queue.enqueue(x.key);
        if (cmp2 > 0)
            keys(x.rchild, queue, lo, hi);
    }

    public Key min() {
        if (isEmpty())
            return null;
        return min(root).key;
    }

    private Node min(Node p) {
        while (p != null) {
            if (p.lchild == null)
                return p;
            p = p.lchild;
        }
        return null;
    }

    public Key max() {
        if (isEmpty())
            return null;
        return max(root).key;
    }

    private Node max(Node p) {
        while (p != null) {
            if (p.rchild == null)
                return p;
            p = p.rchild;
        }
        return null;
    }

    public void deleteMin() {
        root = deleteMin(root);
    }

    public void deleteMax() {
        root = deleteMax(root);
    }

    /** * Unit tests the <tt>BST</tt> data type. */
    public static void main(String[] args) {
        BST<String, Integer> st = new BST<String, Integer>();
        for (int i = 0; !StdIn.isEmpty(); i++) {
            String key = StdIn.readString();
            st.put(key, i);
        }

        for (String s : st.levelOrder())
            StdOut.println(s + " " + st.get(s));

        StdOut.println();

        for (String s : st.keys())
            StdOut.println(s + " " + st.get(s));

        StdOut.println();

    }
}
    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/qing0706/article/details/50592846
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞