我是靠谱客的博主 快乐摩托,最近开发中收集的这篇文章主要介绍算法5-无序链表中的顺序查找、有序数组中的二分查找一、无序链表中的顺序查找二、无序链表中的顺序查找三、总结,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
各位读者,晚上好。这几篇博客陆续介绍下算法中的查找。本篇博客介绍的关于符号表的查找算法是循序渐进的,正因为前一个方法存在的缺点,所以用后一种方法改进;当2种方法都不满意,我们需要突破,寻找新的数据结构。
本博客代码示例均来自:算法 Algorithmes Forth Edition
[美] Robert Sedgewick Kevin Wayne 著 谢路云译
一、无序链表中的顺序查找
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)级别,
* 算法消耗在:比较的次数上
*/
}
二、无序链表中的顺序查找
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)可以类似链表快速插入
* 下一篇博客介绍
*/
}
三、总结
我们知道,用二分法猜数,100以内的整数只需要7次即可猜中;即便很大的数字,猜中的次数不那么可怕,查找中就我目前知道的,没有比二分法更快的了;
不过,世界如果如此简单就好了。
1、二分法高效的前提是数据必须有序
如果给你100个无需的整数,你猜猜试一试?所需很多经典的排序算法就是先把数据高效排序后,然后就可以快速查找了。世界之所以复杂,是因为有很多数据:1是量大;2是把它们排序所花费的精力还不如不排序
2、二分法针对的是静态的数据
如果这个数据是动态的,还会有新数据不断写入,请问你怎么保证顺序?一直不停的排序嘛?也就是二分法无法应对不断有新数据插入的情况
因此,二叉查找树诞生了,下篇博客再会~
最后
以上就是快乐摩托为你收集整理的算法5-无序链表中的顺序查找、有序数组中的二分查找一、无序链表中的顺序查找二、无序链表中的顺序查找三、总结的全部内容,希望文章能够帮你解决算法5-无序链表中的顺序查找、有序数组中的二分查找一、无序链表中的顺序查找二、无序链表中的顺序查找三、总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复