插入排序:
原地排序:这些数字是在数组A中重新排序的,在任何时刻,至多只有其中的常数个数是存储在数组之外的。
插入排序是一种增量排序,主要思想:从1到n遍历数组,并假设遍历之前的数据已排好序(此假设因为从开始迭代故成立),那么就要将当前元素插入到已排序好的元素中的适当位置。
代码如下:
/*
input: a array of integer number,and the count of array
output:none
function:insert_sort the array
*/
void insertSort(int arrayA[], int n)
{
for(int i=1;i<n;i++)
{
int key = arrayA[i];
int j=i-1;
//insert key into array 0...i-1
while(j>=0 && key < arrayA[j])
{
arrayA[j+1] = arrayA[j];
j--;
}
arrayA[j+1] = key;
}
}
选择排序:
主要思想:选择数组中的最小元素与A[0]交换,然后选择次小的元素与A[1]交换,这样不断选择后面的最小元素并与前面的交换,完成排序。
选择排序也是增量排序,也是原地排序
/*
input: a array of integer number,and the count of array
output:none
function:select_sort the array
*/
void selectSort(int arrayA[], int n)
{
for(int i=0;i<=n-1;i++)
{
int min=i;//select the minmum element of i+1...n-1
for(int j=i+1;j<=n-1;j++)
{
if(arrayA[j] < arrayA[min])
min = j;
}//swap the minimum with the i
if(min!=i)
{
int temp = arrayA[i];
arrayA[i] = arrayA[min];
arrayA[min] = temp;
}
}
}
插入排序和选择排序及冒泡排序都是增量排序:在排序好的子数组A[1...i-1]后,将某符合性质的元素插入其中或者放入其后。
Divide-and-conquer分治法:
将原问题划分成N个规模较小而结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,得到原问题的解
分治法要点:
1.将原问题分解成一系列子问题
2.递归地解子问题,如果子问题足够小则直接求解
3.将子问题的解合并成原问题的解
归并排序利用了分治法的原理:
1.将n个待排序元素分成两个n/2的待排序子序列
2.用归并排序对两个n/2规模的子序列进行排序
3.合并已排序好的两个n/2序列为一个n序列元素得到排序结果
合并过程:
// merger array[p..q] and array[q+1...r] to a sorted array
void merge(int arrayA[], int p,int q,int r)
{
int n1 = q-p+1;
int n2 = r-q;
int* tempA=new int[n1+1];
for(int i=0;i<n1;i++)
tempA[i] = arrayA[p+i];
int* tempB = new int[n2+1];
for(int i=0;i<n2;i++)
tempB[i] = arrayA[q+1+i];
tempA[n1] = tempB[n2] = 10000000;//分别为哨兵,省地判断已到末尾
int i=0,j=0;
for(int k=p;k<=r;k++)
{
if(tempA[i] <= tempB[j])
{
arrayA[k] = tempA[i];
i++;
}
else
{
arrayA[k] = tempB[j];
j++;
}
}
delete []tempA;
delete []tempB;
tempA = tempB =NULL;
}
//merge_sort the array from start to end (including start and end)
void mergeSort(int arrayA[],int start,int end)
{
if(start < end)
{
int middle = (start+end)/2;
mergeSort(arrayA,start,middle);
mergeSort(arrayA,middle+1,end);
merge(arrayA,start,middle,end);
}
}
归并排序的思想就是不断分割,将n个元素不断分割下去,最后形成很多(x) (y)的一元组,然后将这些一元组合并起来,形成二元组(x,y)(z,t),再合并这些二元组,形成四元组。。。再合并形成n元组。。。通过将数据不断分割--合并的过程完成整个排序。其中各个元组合并的过程可以用来统计逆序对,对于A[p...q...r]来说,i在p...q之间,j在q+1...r之间,如果A[i] > A[j] ,那么因为A[p...q]和A[q+1...r]已经排序好,那么A[i...q]都将大于A[j],这样逆序对将增加q-i+1个,在这样不断合并的过程中就可以完成逆序对的统计了。主要是要对合并的分割--合并的过程要了解清楚自然就理解了。
总结:第2章主要介绍了几种增量排序和分治法的一个应用---归并排序。对于增量排序而言,是通过将未排序中的元素不断加入到已排序部分中(选择排序是放入后面,插入排序是插入已排序中,冒泡排序中是不断交换)。。。这样未排序元素不断减少已排序部分不断增加,这样完成排序。而分治法主要思想是将一个大问题划分成数个结构相似的小问题,然后去解这些小问题,再将这些小问题的解合并成大问题的解。归并排序就是讲排序n个数分解成排序n/2,n/2个数,再将排序n/2个数分解成两个n/4,n/4个数的情况,这样就形成了一个递归树,然后从最底层开始解起,不断向树根合并小问题的解最终形成大问题的解完成排序。本章还讨论了二分查找等。主要要学会分治法的思想以及排序过程中的步骤这样就能熟练一些已知的问题了。