查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数值元素。
查找表按照操作方式来分有两大种,静态查找表和动态查找表:
(1)静态查找表:只作查找操作的查找表,它主要操作有:
1、查询某个特定数据元素是否在查找表中;
2、检索某个特定数据元素和各种属性。
(2)动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素,它的主要操作有:
1、查找时插入数据元素;
2、查找时删除数据元素。
下面是几种普遍的查找算法以及其实现代码:
1、顺序表查找,线性查找,从第一个记录开始,逐个记录的关键字和给定值进行比较,若相等则查找成功,若直到最后一个都不等,则查找不成功。
//顺序查找法
public static int Sqeuential_Search(int[] array,int key)
{
if (array==null||array.length<0)
return 0;
//结果为:查找成功则返回其位置,否则返回-1
/*
for (int i=0;i<array.length;i++)
{
if (array[i]==key)
return i;
}
return -1;
*/
//对顺序表查找进行优化操作,减少每次都需要对i比较是否越界的问题,可以在数组中放置一个哨兵
array[0]=key;//作为哨兵,免去了每一次比较后都需要判断查找位置是否需要越界的小技巧
int i=array.length-1;
while (array[i]!=key)
i--;
return i;//若返回的是0就代表查找失败
}
2、有序表查找,主要有折半查找或称为二分查找、插值查找以及斐波那契查找的实现代码
1、折半查找:又称二分查找,他的前提就是线性表中的记录必须是关键码有序,线性表必须采用顺序存储
在有序变中,取中间记录作为比较对象,若相等则查找成功,若小于在左边查找,大于在右边查找
2、插值查表法:根据要查找的关键字key与查找表中最大最小记录的关键字比较之后的查找方法,关键在于适用于极端分布不均的数组中
middle=low+((key-arrays[low])/(arrays[high]-arrays[low]))*(high-low);//插值查表法
3、斐波那契查找:基于黄金分割原理
public static int BinarySearch(int[] arrays,int key)
{
int low=0;
int high=arrays.length-1;
int middle;//中位数
while (low<=high)
{
//middle=low+(high-low)/2;//二分查找法
middle=low+((key-arrays[low])/(arrays[high]-arrays[low]))*(high-low);//插值查表法
if (arrays[middle]==key)
return middle;
else if (arrays[middle]>key)
{
high=middle-1;
}
else if (arrays[middle]<key)
low=middle+1;
}
return 0;
}
//斐波那契查找
//生成斐波那契数列
public static int Fibonacci(int n)
{
if (n==0)
return 0;
if (n==1)
return 1;
else
return Fibonacci(n-1)+Fibonacci(n-2);
}
//斐波那契查找
public static int FibonacciSearch(int length,int key)
{
int low=0;
int high=length-1;
int middle,k=0;
while (length>Fibonacci(k)-1)
k++;//找到数组中个数在斐波那契数列中的位置
for (int i=length-1;i<Fibonacci(k)-1;i++)
arrays[i]=arrays[length-1];//将不满的位置补全
while (low<=high)
{
middle=low+Fibonacci(k-1)-1;
if (key<arrays[middle])
{
high=middle-1;
k=k-1;
}
else if (key>arrays[middle])
{
low=middle+1;
k=k-2;
}
else {
if (middle<=length-1)
return middle;
else
return length;
}
}
return 0;
}
3、线性索引查找
a. 稠密索引
b. 分块索引
c. 倒排索引
4、二叉树排序树
二叉排序树又称为二叉查找树,具有以下性质:
a、若它的左子树不空,则左子树所有结点的值均小于它的根结构的值;
b、若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
c、它的左、右子树也分别为二叉排序树。
/**
* 二叉树排序树查找:二叉排序树即表示所有的左孩子都比根结点小,右孩子都比根结点大
*/
public static class BiTNodeNew
{
int data;
BiTNodeNew leftchild;
BiTNodeNew rightchild;
public BiTNodeNew(int data,BiTNodeNew leftchild,BiTNodeNew rightchild)
{
this.data=data;
this.leftchild=leftchild;
this.rightchild=rightchild;
}
}
//创建一个二叉排序树
public static BiTNodeNew CreateBinarySortTree(int[] arrays)
{
BiTNodeNew root;
root=new BiTNodeNew(arrays[0],null,null);
//将数组插入到二叉树中,建立二叉排序树
for (int i=1;i<arrays.length;i++)
InsertSortTree(root,arrays[i]);
return root;
}
public static void InsertSortTree(BiTNodeNew root,int number)
{
BiTNodeNew temp;
while (true)
{//对二叉排序树进行插入操作
temp=new BiTNodeNew(number,null,null);
if (root.data==number)
return;
if (root.data>number)
{
//若输入的数小于根结点的值
if (root.leftchild==null)
{
root.leftchild = temp;
return;
}
else
root=root.leftchild;
}else
{
if (root.rightchild==null)
{
root.rightchild=temp;
return;
}
else
root=root.rightchild;
}
}
}
public static boolean SearchBST(BiTNodeNew tree,int key)
{
if (tree==null)//若为空树查找不成功
return false;
else if (tree.data==key)
return true;
else if (key<tree.data)
{
return SearchBST(tree.leftchild,key);//在左子树中查找
}
else
return SearchBST(tree.rightchild,key);//右子树中查找
}
//二叉排序树插入操作,当二叉排序树中不存在关键字时就将key值插入到合适的位置中去
//插入成功即返回true,否则返回false
public static boolean InsertBST(BiTNodeNew root,int key)
{
BiTNodeNew temp;
if (!SearchBST(root,key))
{//若查找不成功
InsertSortTree(root,key);
return true;
}
else
return false;
}
/**
* 二叉树的删除操作,三种情况的分析
* 1、叶子结点
* 2、仅有左子树和右子树的结点
* 3、左右子树都有的结点
*/
public static boolean DeleteBST(BiTNodeNew root,int key)
{
if (root==null)
return false;
else
{
if (key==root.data)
{
return Delete(root);
}
else if (key<root.data)
//递归实现删除
return DeleteBST(root.leftchild,key);
else
return DeleteBST(root.rightchild,key);
}
}
public static boolean Delete(BiTNodeNew biTNodeNew)
{
BiTNodeNew temp=biTNodeNew;
//分三种情况考虑
if (biTNodeNew.leftchild==null&&biTNodeNew.rightchild==null)
biTNodeNew=null;
else if (biTNodeNew.leftchild==null)
{
//左子树为空的话,只需要将右子树赋给原结点,并将原结点删除
//temp=biTNodeNew;
temp=temp.rightchild;
}
else if (biTNodeNew.rightchild==null)
{//右子树为空的时候
// temp=biTNodeNew;
temp=temp.leftchild;
}
else
{
//考虑左右子树都不为空的时候删除操作
// temp=biTNodeNew;
BiTNodeNew nodeNew=biTNodeNew;
nodeNew=nodeNew.leftchild;
while (nodeNew.rightchild!=null)
{
temp=nodeNew;
nodeNew = nodeNew.rightchild;//找到左边最接近该结点的值
}
biTNodeNew.data=nodeNew.data;
if (temp!=biTNodeNew)
temp.rightchild=nodeNew.leftchild;//重接temp的右子树
else
{
temp.leftchild=nodeNew.leftchild;
}
}
return true;
}