插入排序及其时间复杂度推导

算法研究的基本步骤

1、了解基本思想,我觉得在算法中最重要的就是基本思想,它是算法的灵魂
2、说明算法,也就是表达算法,将算法用伪码表达出来
3、证明算法的正确性
4、分析算法的复杂度

算法基本思想

对于一个输入的序列或者称之为数组,插入排序要做的就是将其分成两部分,一部分是有序的,一部分是无序的。在第一次进行划分的时候,只能将第一个元素视为有序的。然后从无序的部分中从前向后依次取元素,去跟有序的部分进行比较。在有序部分进行比较的时候是即可以从后向前比较,也可以从前向后比较。直到发现自己合适的位置,然后插入进去。这样,无序部分中的元素向有序部分流动,流动的时候通过比较来保证有序部分的顺序。

伪代码1
算法名称:插入排序
输入:n个数的数组a
输出:有序的数组a

for i = 2 to n
	x = a[i]
	p = 1
	for j = i-1 down to 1
		if a[j] > x
			a[j+1]←a[j]
		else 
			p = j+1; break
		end if
	end for
	a[p]←x
end for

伪代码2
算法名称:插入排序
输入:n个数的数组a
输出:有序的数组a

for i = 2 to n
	key = a[i]
	j = i-1
	while j > 0 && a[j] > key
		a[j+1] = a[j]
		j = j-1
	a[j+1] = key

这里给出了两种伪码,其中伪码2是来自《算法导论》的。之所以没有加注释,是为了使读者在阅读的时候能够思考每一行表达的意思。
比较可以发现,第二种伪码更便于理解,第一种伪码多了一个变量p,一方面占用了过多的内存,另一方面使得前后逻辑难于理解。
另外伪码中的下标是从1开始的,而实际编程是下标是从0开始的。

算法实现

Java的实现

public static void main(String[] args) {
	int[] a = {55,23,45,16,8,7,22,15,20,13};
	
	for(int j = 1;j<a.length;j++) {
		int key = a[j];
		int i = j-1;
		while(i >= 0 && a[i]>key) {
			a[i+1] = a[i];
			i = i-1;
		}
		a[i+1] = key;
	}
	
	// 输出排序完的数组
	for(int i : a) {
		System.out.println(i);
	}
}

最好时间复杂度

该算法的基本运算是while j > 0 && a[j] > key
以第二种伪码为例。插入排序,当输入的数组是有序的数组时,插入排序的内层while循环只需进行比较一次就会结束循环,而外层循环会依次执行完。所以可以得到如下函数: T b e s t ( n ) = ∑ i = 2 n 1 = n − 1 = O ( n ) T_{best}(n)=\sum^n_{i=2}1=n-1=O(n) Tbest(n)=i=2n1=n1=O(n)

最坏时间复杂度

以第二种伪码为例。插入排序,当输入的数组是逆向排序好的数组时,插入排序的内层while循环需要进行比较所有的情况才会结束循环,而外层循环会依次执行完。外层循环执行的次数前面已经分析过,在最坏的情况下,内层循环结束的条件是 ′ j = 0 ′ 'j=0' j=0,也就是 j j j i − 1 i-1 i1一直减到0,基本运算运行了 i − 1 i-1 i1次。所以可以得到如下函数: T w o r s t ( n ) = ∑ i = 2 n ( i − 1 ) = 1 + 2 + . . . + n − 1 = n ( n − 1 ) 2 = O ( n 2 ) T_{worst}(n)=\sum^n_{i=2}(i-1)=1+2+...+n-1=\frac{n(n-1)}{2}=O(n^2) Tworst(n)=i=2n(i1)=1+2+...+n1=2n(n1)=O(n2)


你可能感兴趣的:(算法和建模)