各种排序

插入排序算法

插入排序是最简单的排序算法。插入排序有N-1趟排序组成。对于P=1趟到P=N-1趟,插入排序保证从位置0到位置P上的元素已为排序状态。插入排序利用了这样的事实:位置0到位置P-1上的元素是排过序的。图1显示一个简单的数组在每一趟排序后的情况。

各种排序

图1:每趟后的插入排序

如下代码实现了上述想法:

 

void InsertionSort(ElementType A[], int N)

{

	int j, p;

	ElementType Tmp;

	for (p = 1; p < N; ++p){

		Tmp = A[p];

		for (j = p; A[j - 1] > Tmp && j > 0; --j){

			A[j] = A[j - 1];

		}

		A[j] = Tmp;

	}

}

 

在第2行到第5行实现数据移动而没有明显使用交换。位置P上的元素存于Tmp,而在位置P之前所有更大的元素都被向右移动一个位置。然后Tmp被置于正确的位置上。

从代码中可以看出,插入排序复杂度是O(N^2),但如果输入数据已预先排序,那么运行时间为O(N)。

希尔排序

通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止。所以希尔排序也叫缩小增量排序。希尔排序使用一个序列h1,h2,....,hn,叫做增量序列,只要h1=1,任何增量序列都是可以的,不过有些增量序列比另外一些增量序列更好。在使用增量hk的一趟排序后,对于每一个i,我们有A[i] <= A[i+hk],即所有相隔hk的元素都被排序,此时和排序文件是hk-排序的。希尔排序的一个重要性质是:一个hk-排序的文件保持它的hk-排序性。如果情况不是这样的话,希尔排序也就没有意义了。

hk-排序的一般做法是:对于hk,hk+1,...,N-1中的每一个位置i,把其上的元素放到i,i-hk,i-2*hk....中间的正确位置上。一趟hk排序的作用就是对hk个独立的子数组执行一次插入排序。

希尔排序的运行时间依赖于增量序列,但最坏情形下的运行时间为O(N^2),但对于有些增量序列,其时间可减少到O(N^1.2)。以下是以增量序列:1,2,4,N/2的一种实现:

 

void Shellsort(ElementType A[], int N)

{

	int i, j, Increment;

	ElementType Tmp;



	for (Increment = N / 2; Increment > 0; Increment /= 2){

		for (i = Increment; i < N; ++i){

			Tmp = A[i];

			for (j = i; j >= Increment; j -= Increment){

				if(Tmp < A[j-Increment])

					A[j] = A[j - Increment];

				else

					break;

			}

			A[j] = Tmp;

		}

	}

}

 

 

堆排序

堆排序主要是从二叉堆中通过删除最小元(树根)而得。回忆一下,建立N个元素的堆,需要线性O(N)的时间,然后执行N次DeleteMin操作。按照顺序,最小的元素先离开该堆。通过将这些元素离开的顺序即可得到N个元素的排序,因此总的时间复杂度是O(NlogN)。经验指出,堆排序是一个非常稳定的算法,它平均使用的比较只比最坏情形界指出的略少。执行堆排序的代码如下:

 

#define LeftChild(i) (2 * (i) + 1)



void PercDown(ElementType A[], int i, int N)

{

	int child;

	ElementType Tmp;



	for (Tmp = A[i]; LeftChild(i) < N; i = child){

		child = LeftChild(i);

		if (child != N - 1 && A[child + 1] > A[child])

			++child;				//找到最大的儿子节点

		if (Tmp < A[child])

			A[i] = A[child];

		else

			break;

	}

	A[i] = Tmp;

}



void HeapSort(ElementType A[], int N)

{

	int i;

	for (i = N / 2; i >= 0; --i)

		PercDown(A, i, N);			//构造堆

	for (i = N -1; i > 0; --i){

		Swap(&A[0], &A[i]);			//将最大元素(根)与数组末尾元素交换,从而删除最大元素,重新构造堆

		PercDown(A, 0, i);

	}

}


 


 

你可能感兴趣的:(排序)