`

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

阅读更多
马上要自考了,其中有一门数据结构,好久没复习,忘得差不多了,今天从头开始,顺便记一下笔记。我看的是Java数据结构和算法这本书,所以这里的数据结构和算法全都用Java语言描述。每篇笔记都会附上随书的Applet演示程序,有算法看不明白的,可以下载Applet运行起来(直接打开html文件即可),可以很容易地看清楚算法的每一步。

二分查找法和线性查找法

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

大O表示法

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

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

无序数组和有序数组

下面是两个简单数组类,其中无序数组的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;
	}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics