Bonsoir, lecteurs. Ces blogs introduisent successivement la recherche dans l'algorithme. L'algorithme de recherche de la table des symboles présenté dans ce blog est progressif. En raison des lacunes de la méthode précédente, cette dernière méthode est utilisée pour s'améliorer; lorsque les deux méthodes ne sont pas satisfaisantes, nous devons percer et trouver de nouvelles structures de données.
Les exemples de code pour ce blog proviennent de: Algorithm Algorithm Forth Edition
[US] Robert Sedgewick Kevin Wayne de Xie Luyun
1. Ordre de recherche dans une liste chaînée non ordonnée
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)级别,
* 算法消耗在:比较的次数上
*/
}
Deuxièmement, la recherche séquentielle dans la liste chaînée non ordonnée
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. Résumé
Nous savons qu'en utilisant la dichotomie pour deviner le nombre, un entier sur 100 ne doit être deviné que 7 fois; même pour un grand nombre, le nombre de suppositions n'est pas si terrible. Pour autant que je sache au moment de la recherche, il n'y a pas plus rapide que la dichotomie. De
Cependant, ce serait bien si le monde était si simple.
1. La condition préalable pour que la dichotomie soit efficace est que les données doivent être ordonnées.Si
on vous donne 100 entiers inutiles, devinez quoi? De nombreux algorithmes de tri classiques sont nécessaires pour trier efficacement les données, puis vous pouvez les trouver rapidement. Le monde est compliqué car il y a beaucoup de données: 1 est une grande quantité; 2 est l'énergie dépensée pour les trier n'est pas aussi bon que ne pas trier
2. La dichotomie vise des données statiques.
Si ces données sont dynamiques, de nouvelles données seront continuellement écrites. Comment assurez-vous la commande? Continuez-vous à trier? Autrement dit, la dichotomie ne peut pas faire face à la situation où de nouvelles données sont constamment insérées
Par conséquent, l'arbre de recherche binaire est né et le prochain blog se rencontrera à nouveau ~