实验三-查找与排序-3
参考http://www.cnblogs.com/maybe2030/p/4715035.html 在Searching中补充查找算法并测试
提交运行结果截图
斐波那契查找
-
1.斐波那契数列
斐波那契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、····,在数学上,斐波那契被递归方法如下定义:F(1)=1,F(2)=1,F(n)=f(n-1)+F(n-2) (n>=2)。该数列越往后相邻的两个数的比值越趋向于黄金比例值(0.618)。 -
2.实现思路
我认为斐波那契查找和二分查找的区别不大,唯一的区别是二分查找的划分是对半分,而斐波那契查找是根据斐波那契数列进行的划分。但我们知道斐波那契查找的算法复杂度依旧是O(log 2 n ),而且实现还很复杂,所以斐波那契查找相较于二分查找的好处是在每次计算mid的值的时候避免了"除法",只是涉及到了"加法和减法",而除法的运算本身就比加减法更加占用时间。
如何进行查找。之所以斐波那契查找避免了除法,是因为我们一开始构造了一个斐波那契数列,每次划分只需要从数列中拿出相应的两个数就行。斐波那契数列:1、1、2、3、5、8、13、21、34、55、89……从第三个数开始,每个数等于前两个数的和,巧妙利用这一点我们在每次比较后对于mid的赋值就不必像二分查找mid = (first + last ) / 2
,而是mid = first+fib[idex-1]-1
,fib是我们构造的一个斐波那契数列,正是要利用斐波那契数列的特点进行分割,我们就必须根据要进行查找的数组来从fib数组中确定一个数m.这里会出现两种情况:(1)数组长度刚好符合fib数列中的某个数;(2)fib数组找不到恰当的数,这时候就需要将原数组进行扩充,我们采用重复填入最后一个数。如果m = fib[n],那么第一次划分就将数组分为两个部分它们分别含有fib[n-1]和fib[n-2]个元素,然后进行比较,再根据比较的结果再对数组进行划分。
public static Comparable FibonacciSearch(Comparable[] data, Comparable target) {
int idex = 0;
int[] fib = SetFibonacci();
while (data.length>fib[idex]){
idex++;
}
Comparable[] fibdata = new Comparable[fib[idex]];
;
for (int i = 0;i<fibdata.length;i++){
if (i<data.length){
fibdata[i] = data[i];
}
else
fibdata[i] = data[data.length-1];
}
int first=0;
int last = fibdata.length-1;
int mid = 0;
while (first<= last){
mid = first+fib[idex-1]-1;
if (fibdata[mid].compareTo(target)>0){
last = mid;
idex = idex-1;
}
else if (fibdata[mid].compareTo(target)<0){
first = mid;
idex = idex-2;
}
else {
if (mid<=last)
return mid;
else
return last;
}
}
return -1;
}
//构造Fibonacci数列
public static int[] SetFibonacci() {
int[] fib = new int[20];
int i = 0;
fib[0] = 1;
fib[1] = 1;
for (i = 2; i < fib.length; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib;
}
插值查找
- 原理:插值查找的主要思路就是划分数组的查找点是自适应,所以该查找的前提是有序数列元素的值是成线性增长的。
二分查找中查找点计算如下:
mid=(low+high)/2, 即mid=low+1/2(high-low);
通过类比,我们可以将查找的点改进为如下:
mid=low+(key-a[low])/(a[high]-a[low])(high-low),
也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。
- 加入我们要在[1,100]中找到15,我们设15的下标为m,第一个数的下标(first),第二个数的下标(last),由于数列线性增长,我们不难得到(m-first)/(last-first) ≈ (15-A[first])/(A[last]-A[first])进而得到:m = first + (15-A[first])/(A[last]-A[first])*(last-first).
public static Comparable InsertionSearch(Comparable[] data, Comparable target, int key, int low, int hight) {
if (key < low || key > hight || low < hight) {
throw new NumberFormatException("Wrong number");
} else {
int mid;
Comparable result = null;
while (result == null && low <= hight) {
mid = low + (key - low) / (hight - low) * (hight - low);
if (data[mid].compareTo(target) == 0) {
result = data[mid];
} else if (data[mid].compareTo(target) > 0)
hight = mid - 1;
else
low = mid + 1;
}
return result;
}
}
实验三-查找与排序-4
补充实现课上讲过的排序方法:希尔排序,堆排序,桶排序,二叉树排序等
测试实现的算法(正常,异常,边界)
提交运行结果截图
推送相关代码到码云上
堆排序
- 利用已经完善的类LinkedMaxHeap,现将要排序的数组的元素加入到堆(最大)中,利用removeMax()方法将元素按照从大到小输出。
public static void HeapSort(Comparable[] data){
LinkedMaxHeap myTree = new LinkedMaxHeap();
for (int i=0;i<data.length;i++){
myTree.add(data[i]);
}
for (int i=0;i<data.length;i++){
data[i]=myTree.removeMax();
}
}