1.概念
查找就是在某种数据结构形式存储的数据集合中,找出满足指定条件的结点,若查找成功,给出记录信息或者记录在表中的位置,如果查找不成功,返回空
查找的三种方式
1.线性表的查找
(1) 顺序查找
原理: 从表的一端开始,逐个对记录和给定的关键字进行比较,如果找到一个记录与给定的记录一样,那么查找成功,如果没有一样的那么就查找失败
时间复杂性:O(n)
优缺点:顺序查找的优点是算法简单,对表结构没有要求,不需要排序,缺点是平均查找长度较大,查找效率低
示例代码
public class OrderSearch {
public static int orderSearch(int searchKey,int... array){
for(int i=0;i<array.length;i++){
if(array[i]==searchKey){
return i;
}
}
return -1;
}
/**测试查找结果
* @param args
*/
public static void main(String[] args) {
int[] test=new int[]{1,2,29,3,95,3,5,6,7,9,12};//升序序列
int index=OrderSearch.orderSearch(95, test);
System.out.println("查找到的位置 :"+ index);
}
}
(2)折半查找
原理:假设查找表的元素存储在数组[1….n],首先将待查的key值与表中间位置上(下标为mid)的纪录的关键字进行比较,若相等,则查找成功,如果key>r[mid].key,那就说明待查记录在后半个子表r[mid+1….n],下一步应该在后半个子表中查找如果key
public class SplitFind {
/**
* @author hbliu
* @param arrayData 数组
* @param searchData 要查找的数据
* @param start 开始下标
* @param end 结束下标
* @return 数据在数组中下标的位置,如果数据不在数组中,返回 -1
* 功 能:折半查找
*/
public static int splitHalf(int[] arrayData,int searchData,int start,int end){
int index = (start + end)/2;
int data = arrayData[index];
if(start > end ){
return -1;
}
if(data == searchData){
return index;
}else{
if(data < searchData){
return splitHalf(arrayData,searchData,index+1,end);
}else{
return splitHalf(arrayData,searchData,start,index-1);
}
}
}
/**
* @author hbliu
* @param args
*/
public static void main(String[] args) {
int[] array = { 3,5,11,17,21,23,28,30,32,50};
System.out.println(array.length);
int isExist = splitHalf(array,(int)50,0,array.length - 1);
System.out.println("isExist : "+isExist);
}
}
2.树表的查找(动态查找)
(1)二叉树 是一种对排序和查找都很有用的特殊二叉树
二叉树的性质: 左子树一定小于它的根节点 右子树一定大于根节点
二叉树重要性质为中序遍历可以得到一个节点值递增的有序序列
查找原理:
(1)如果排序树为空,则查找失败,返回空
(2) 若二叉排序树非空,将给定的值key 与根节点进行比较
如果 key 等于,那就查找成功 返回根节点的地址
如果key 小于根节点那么就查找左子树
如果key 大于根节点,则进一步查找右节点子树
时间复杂度 O(log2n)
例子
public class BinarySortTree {
private Node root = null;
/**查找二叉排序树中是否有key值*/
public boolean searchBST(int key){
Node current = root;
while(current != null){
if(key == current.getValue())
return true;
else if(key < current.getValue())
current = current.getLeft();
else
current = current.getRight();
}
return false;
}
/**向二叉排序树中插入结点*/
public void insertBST(int key){
Node p = root;
/**记录查找结点的前一个结点*/
Node prev = null;
/**一直查找下去,直到到达满足条件的结点位置*/
while(p != null){
prev = p;
if(key < p.getValue())
p = p.getLeft();
else if(key > p.getValue())
p = p.getRight();
else
return;
}
/**prve是要安放结点的父节点,根据结点值得大小,放在相应的位置*/
if(root == null)
root = new Node(key);
else if(key < prev.getValue())
prev.setLeft(new Node(key));
else prev.setRight(new Node(key));
}
/**
* 删除二叉排序树中的结点
* 分为三种情况:(删除结点为*p ,其父结点为*f)
* (1)要删除的*p结点是叶子结点,只需要修改它的双亲结点的指针为空
* (2)若*p只有左子树或者只有右子树,直接让左子树/右子树代替*p
* (3)若*p既有左子树,又有右子树
* 用p左子树中最大的那个值(即最右端S)代替P,删除s,重接其左子树
* */
public void deleteBST(int key){
deleteBST(root, key);
}
private boolean deleteBST(Node node, int key) {
if(node == null) return false;
else{
if(key == node.getValue()){
return delete(node);
}
else if(key < node.getValue()){
return deleteBST(node.getLeft(), key);
}
else{
return deleteBST(node.getRight(), key);
}
}
}
private boolean delete(Node node) {
Node temp = null;
/**右子树空,只需要重接它的左子树
* 如果是叶子结点,在这里也把叶子结点删除了
* */
if(node.getRight() == null){
temp = node;
node = node.getLeft();
}
/**左子树空, 重接它的右子树*/
else if(node.getLeft() == null){
temp = node;
node = node.getRight();
}
/**左右子树均不为空*/
else{
temp = node;
Node s = node;
/**转向左子树,然后向右走到“尽头”*/
s = s.getLeft();
while(s.getRight() != null){
temp = s;
s = s.getRight();
}
node.setValue(s.getValue());
if(temp != node){
temp.setRight(s.getLeft());
}
else{
temp.setLeft(s.getLeft());
}
}
return true;
}
/**中序非递归遍历二叉树
* 获得有序序列
* */
public void nrInOrderTraverse(){
Stack<Node> stack = new Stack<Node>();
Node node = root;
while(node != null || !stack.isEmpty()){
while(node != null){
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
System.out.println(node.getValue());
node = node.getRight();
}
}
public static void main(String[] args){
BinarySortTree bst = new BinarySortTree();
/**构建的二叉树没有相同元素*/
int[] num = {4,7,2,1,10,6,9,3,8,11,2, 0, -2};
for(int i = 0; i < num.length; i++){
bst.insertBST(num[i]);
}
bst.nrInOrderTraverse();
System.out.println(bst.searchBST(10));
bst.deleteBST(2);
bst.nrInOrderTraverse();
}
/**二叉树的结点定义*/
public class Node{
private int value;
private Node left;
private Node right;
public Node(){
}
public Node(Node left, Node right, int value){
this.left = left;
this.right = right;
this.value = value;
}
public Node(int value){
this(null, null, value);
}
public Node getLeft(){
return this.left;
}
public void setLeft(Node left){
this.left = left;
}
public Node getRight(){
return this.right;
}
public void setRight(Node right){
this.right = right;
}
public int getValue(){
return this.value;
}
public void setValue(int value){
this.value = value;
}
}
}
树的查找还分B+树的查找和B-树的查找 此处略过
散列表的查找方法
散列表的基本思想:通过对元素的关键字值进行某种运算,直接求出元素的地址,即用关键字到地址的直接转换的方法
概念:
散列函数和散列地址:在记录的存储地址p和其关键字key之间建立一个确定的对应关系H 使得p=H(key),称这个对应关系H为散列函数,P为散列地址
散列表:一个有限连续的地址空间,通常散列表的存储空间就是一个一维数组,散列地址就是数组的下标
冲突和同义词: 对不同的关键字可能得到同一个散列地址 就是 key1!=key2 但是H(key1)==H(key2)
构造散列函数的几种方法
数字分析法: 如果每个关键字的位数比散列表的地址码多,每个关键字由n位数组成,如 k1k2k3k4,那么可以从关键字中提取数字分别均匀的几位或者若干位作为散列地址
平方取中法: 一个数平方后的中间几位和数的每一位都是相关的,如果取关键字平方后的中间几位作为散列地址,那么散列地址就是随机的
折叠法:将关键字分割成位数相同的几部分,取这几部分进行舍位相加。
除留余数法: 假关键m设散列表表长,选择一个不大于m的数p 用P去除关键字 除后余数为散列地址 一般取p为表长的最大的质数。
H(key)=key%p
示例代码
package 散列表;
import java.util.Random;
public class HashProcess {
public static void main(String[] args) {
int[] arr = new int[10];
int[] hashTable = new int[arr.length*2+1];
Random random = new Random();
for(int i=0 ; i<arr.length ; i++){
arr[i] = random.nextInt(10)%10+10;
}
for(int a : arr){
InsertHash(hashTable,a);
System.out.print(a + " ");
}
System.out.println(SearchHash(arr[6],hashTable.length,hashTable));
}
private static boolean SearchHash(int a,int len,int[] ht) {
int addr = Hash(a,len);
while(ht[addr] != a){
addr = (addr+1)%len;
if(ht[addr] == 0 || addr == Hash(a,len)){
return false;
}
}
return true;
}
private static void InsertHash(int[] hashTable, int a) {
int len = hashTable.length;
int addr = Hash(a,len);
while(hashTable[addr] != 0){
addr = (addr+1)%len;
}
hashTable[addr] = a;
}
private static int Hash(int a,int len) {
return a%len;
}
}