Algorithm 5-Order search in unordered linked list, binary search in ordered array

Good evening, readers. These blogs successively introduce the search in the algorithm. The search algorithm for the symbol table introduced in this blog is gradual. Because of the shortcomings of the previous method, the latter method is used to improve; when the two methods are not satisfactory, we need to break through and find new data structures.

The code examples for this blog are from: Algorithm Algorithm Forth Edition
[US] Robert Sedgewick Kevin Wayne by Xie Luyun

1. Order search in unordered linked list

package com.cmh.algorithm;

/**
 * @author: 起舞的日子
 * @date: 2020/4/6 下午11:24
 * 符号表:基于无序链表的顺序查找
 * ST = Symbol Table
 */
public class SequentialSearchST<Key, Value> {

    private Node first;//链表首节点

    private class Node {
        //链表节点定义
        Key key;
        Value value;
        Node next;

        public Node(Key key, Value value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }

    public Value get(Key key) {
        //根据给定的键返回对应的值
        for (Node x = first; x != null; x = x.next) {
            if (key.equals(x.key)) {
                return x.value;//命中  如果key是对象,要考虑对象对象等价性
            }
        }
        return null;//未命中
    }

    public void put(Key key, Value val) {
        //根据给定的键,找到则更新其值,否则在表中新建节点
        for (Node x = first; x != null; x = x.next) {
            if (key.equals(x.key)) {
                x.value = val;
                return;
            } else {
                first = new Node(key, val, first); //未命中,新建节点p
            }
        }
    }

    /**
     * 使用无序链表实现K,V查找和插入,最大问题是数据量很大时候,算法复杂度至少在O(N)级别,
     * 算法消耗在:比较的次数上
     */
}

Second, the sequential search in the unordered linked list

package com.cmh.algorithm;

import edu.princeton.cs.algs4.Queue;

import static edu.princeton.cs.algs4.BinaryStdIn.isEmpty;

/**
 * @author: 起舞的日子
 * @date: 2020/4/6 下午11:40
 * 符号表:基于有序数组的二分查找
 */
public class BinarySearchST<Key extends Comparable<Key>, Value> {
    private Key[] keys;
    private Value[] vals;
    private int N;

    public BinarySearchST(int capacity) {
        //调整数组大小... 省略
        keys = (Key[]) new Comparable[capacity];
        vals = (Value[]) new Object[capacity];
    }

    public int size() {
        return N;
    }

    public Value get(Key key) {
        if (isEmpty()) {
            return null;
        } else {
            int i = rank(key);
            if (i < N && keys[i].compareTo(key) == 0) {
                return vals[i];
            } else {
                return null;
            }
        }
    }

    //基于有序数组的二分查找(无递归调用)
    public int rank(Key key) {
        int lo = 0, hi = N - 1;
        while (lo <= hi) {
            int mid = lo + (hi - lo) / 2;
            int cmp = key.compareTo(keys[mid]);
            if (cmp < 0) {
                hi = mid - 1;
            } else if (cmp > 0) {
                lo = mid + 1;
            } else {
                return mid;
            }
        }
        return lo;
    }

    /**
     * 还可以用递归方式实现二分查找
     */
    public int rank(Key key, int lo, int hi) {
        if (hi < lo) {
            return lo;
        }
        int mid = lo + (hi - lo) / 2;
        int cmp = key.compareTo(keys[mid]);
        if (cmp < 0) {
            return rank(key, lo, mid - 1);
        } else if (cmp > 0) {
            return rank(key, mid + 1, hi);
        } else {
            return mid;
        }
    }

    public void put(Key key, Value val) {
        //查找键,找到则更新值,否则创建新元素
        int i = rank(key);
        if (i < N && keys[i].compareTo(key) == 0) {
            vals[i] = val;
            return;
        }
        for (int j = N; j > i; j--) {
            keys[j] = keys[j - 1];
            vals[j] = vals[j - 1];
        }
        keys[i] = key;
        vals[i] = val;
    }

    public Key min() {
        return keys[0];
    }

    public Key max() {
        return keys[N - 1];
    }

    public Key select(int k) {
        return keys[k];
    }

    public Key ceiling(Key key) {
        int i = rank(key);
        return keys[i];
    }

    public Iterable<Key> kes(Key lo, Key hi) {
        Queue<Key> q = new Queue<>();
        for (int i = rank(lo); i < rank(hi); i++) {
            q.enqueue(keys[i]);

        }
/*
        if(contains(hi)){
            q.enqueue(keys[rank(hi)]);

        }
*/
        return q;
    }
    /**
     * 总结:
     * 二分查找优点:
     * 1、查找算法复杂度是对数log级别的
     *
     * 缺点:
     * 1、数据需有序;
     * 2、把很大量的数据排序在很多情况下复杂度会大大提升;
     * 3、有些数据查找和插入是混合进行的,排序好的静态数据就不合适;
     *
     *
     * 所以需要一种新的数据结构,可以结合二分查找的优缺点:
     * 二叉查找树
     * 1)可以用二分法快速查找;
     * 2)可以类似链表快速插入
     * 下一篇博客介绍
     */
}

3. Summary

We know that by using the dichotomy to guess the number, an integer within 100 only needs to be guessed 7 times; even for a large number, the number of guesses is not so terrible. As far as I know at the time of the search, there is no faster than the dichotomy. Of

However, it would be nice if the world were so simple.
1. The prerequisite for the efficient dichotomy is that the data must be ordered.
If you are given 100 unnecessary integers, do you guess? Many classic sorting algorithms are required to sort the data efficiently, and then you can quickly find it. The world is complicated because there are a lot of data: 1 is a large amount; 2 is the energy spent sorting them is not as good as not sorting

2. The dichotomy is aimed at static data.
If this data is dynamic, new data will be continuously written. How do you ensure the order? Do you keep sorting? That is, the dichotomy cannot cope with the situation where new data is constantly inserted

Therefore, the binary search tree was born, and the next blog will meet again ~

Published 181 original articles · praised 66 · 200,000 views

Guess you like

Origin blog.csdn.net/meiceatcsdn/article/details/105355075
Recommended