《Java数据结构和算法》学习笔记(1)——数组 二分法 大O表示法

本文介绍了数据结构中的二分查找法与线性查找法,并通过具体实例解释了这两种方法的工作原理。同时,还探讨了不同查找算法的时间复杂度,利用大O表示法评估算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[b]马上要自考了,其中有一门数据结构,好久没复习,忘得差不多了,今天从头开始,顺便记一下笔记。我看的是[url="http://www.douban.com/subject/1144007/"]Java数据结构和算法[/url]这本书,所以这里的数据结构和算法全都用Java语言描述。每篇笔记都会附上随书的Applet演示程序,有算法看不明白的,可以[url="http://yuan.iteye.com/topics/download/cf39c9aa-40d3-3d9c-b0c6-bd7316add714"]下载Applet[/url]运行起来(直接打开html文件即可),可以很容易地看清楚算法的每一步。[/b]

[size=large][align=center][b]二分查找法和线性查找法[/b][/align][/size]
[b]二分查找[/b]法是一种比普通线性查找快得多的查找算法,但只适用于有序集合当中。拿[b]升序[/b]排序后的[b]整型[/b]数组来说,二分法具体的实现原理是:先把[b]待查找数[/b]a与[b]数组中间的那个数[/b]x对比,如果相等,直接返回x的索引;如果a大于x,则排除掉[b]数组的前面一半[/b](包括x),接着拿a与[b]剩下一半数组[/b]中间的那个数x对比,如果相等,直接返回x的索引;如果a小于x,则排除掉数组[b]后面一半的后面一半[/b]……如此循环直到找到目标。
普通的[b]线性查找[/b]法是从数组的第一个数开始对比,接着是第二个,第三个……直到找到目标。

[size=large][align=center][b]大O表示法[/b][/align][/size]
[b]大O表示[/b]法是一种粗略试题算法效率的方法。了解大O表示法之前先看一组公式:
[b]无序数组[/b]的插入是与数组中数据项个数无关的算法,由于插入时不必考虑排序,新数据项总是被放在下一个有空的地方。我们可以说向一个无序数组中插入一个数据项的时间T是一个[b]常量K[/b](K值与cpu运行速度、编译程序生成程序代码的效率等有关),得出:
[b]T = K[/b]
在数据项的线性查找中,[b]最好的情况下[/b]比较次数只有1次(数组第1个数据项就是所要查找目标的情况);[b]最坏的情况下[/b]比较次数有N(数组长度)次(数组最后一个数据项是查找目标)。平均次数为N/2次,搜索时间T与N/2成正比,也就是与N成正比:
[b]T = K*N[/b]
二分查找法……先反过来思考一个问题:只给5次比较机会,能搜索到目标的最大范围数组长度是多少?1次能比较2个,2次能比较4个,3次能比较8个,4次16个,5次32个。设[b]数组长度[/b]为N,[b]比较次数[/b]为X,N是2的X次方,也就是说X是以2为底N的对数即log2(N)。由此得出二分查找法在最坏情况下花费的时间T为比较次数log2(N)乘以单次比较所花费的时间K,即:
[b]T = K*log2(N)[/b]
也就是T与log2(N)成正比。由于任何对数都和其他对数成比例,我们也可以说T与log(N)(以10为底N的对数)成正比,即:
[b]T = K*log(N)[/b]

大O表示法同上面的公式比较类似,但它省去了常数K。因为比较算法时不需要在乎硬件设备等。大O表示法使用大写字母O,可以使用大O表示法来描述线性查找使用了O(N)级时间,二分查找使用了O(log N)级时间,向一个无序数组插入数据使用了O(1)(或常数)级时间。

[size=large][b][align=center]无序数组和有序数组[/align][/b][/size]
下面是两个简单数组类,其中无序数组的add方法直接向成员array中插值,时间复杂度用大O表示法表示为O(1);有序数组的add方法平均要经过N/2次比较,不考虑插入值之前向后移动数组所花时间(当然这很花时间),时间复杂度为O(N);无序数组的delete方法首先要调用私有的find方法,这里find方法使用线性查找法,时间复杂度为O(N);有序数组的delete方法所调用的binarySearch是二分查找法,时间复杂度为O(log N)。
结论是:
1、无序数组插值效率比有序数组要高得多(有序数组插值时除了比较数据还要移动数组);
2、有序数组删除数据的效率比无序数组高(两种数组在删除数据时都要移动数组,只在查找数据的算法上有区别)。

无序数组类:
package dsaa.array;
/**
* @(#)SortedArray.java 2008-12-24 下午06:36:22
*
* @author Qiu Maoyuan
* Unsorted Array
*/
public class UnsortedArray {

private int[] array;
private int size = 0;

public UnsortedArray(int initialCapacity){
this.array = new int[initialCapacity];
}

public UnsortedArray(){
this(10);
}

public void add(int number){
ensureCapacity();
array[size++] = number;
}

public int get(int index){
if(index>=size)
throw new IndexOutOfBoundsException();
return array[index];
}

public boolean delete(int value){
int index = find(value);
if(index==size)
return false;
moveFrontwards(index);
size--;
return true;
}

private void ensureCapacity() {
if(size==array.length){
int[] newArray = new int[size * 3 / 2 + 1];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray;
}
}

private int find(int value){
int i = 0;
while(i<size && array[i]!=value) i++;
return i;
}

private void moveFrontwards(int startingIndex){
for(int i=startingIndex; i<size-1; i++)
array[i] = array[i+1];
}
}


有序数组类:
package dsaa.array;
/**
* @(#)SortedArray.java 2008-12-24 下午06:36:22
*
* @author Qiu Maoyuan
* Sorted Array
*/
public class SortedArray {

private int[] array;
private int size = 0;

public SortedArray(int initialCapacity){
this.array = new int[initialCapacity];
}

public SortedArray(){
this(10);
}

public void add(int value){
if(size==0){
array[0] = value;
size++;
return;
}

ensureCapacity();

for(int i=0; i<size+1; i++){
if(value<array[i]){
moveBackwards(i);
array[i] = value;
size++;
return;
}
}

array[size] = value;
size++;
}

public int get(int index){
if(index>=size)
throw new IndexOutOfBoundsException();
return array[index];
}

public boolean delete(int value){
int index = binarySearch(value);
if(index==size)
return false;
moveFrontwards(index);
size--;
return true;
}

public int getSize(){
return this.size;
}

private void ensureCapacity() {
if(size==array.length){
int[] newArray = new int[size * 3 / 2 + 1];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray;
}
}

private void moveBackwards(int startingIndex) {
for(int j=size; j>startingIndex; j--){
array[j] = array[j-1];
}
}

private void moveFrontwards(int startingIndex){
for(int i=startingIndex; i<size-1; i++)
array[i] = array[i+1];
}

private int binarySearch(int target){
if(size==0) return size;
int currentIndex;
int lowerBound = 0;
int upperBound = size - 1;
while(true){
currentIndex = (lowerBound + upperBound) / 2;
int currentValue = array[currentIndex];
if(currentValue==target)
break;
else if(currentValue<target){
lowerBound = currentIndex + 1;
}else{
upperBound = currentIndex - 1;
}
if(lowerBound>=upperBound) return size;
}
return currentIndex;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值