第一天 主题:排序算法
排序算法是经常使用的算法,我们一定要把每一个步骤都想清楚,而且用代码实现,这样才能使我们在算法路上走得更远。
什么是排序算法的稳定性?
如果在元素序列中有两个元素R[i]和R[j],关键码K[i]=k[j],且在排序之前R[i]在R[j]的前面,在排序之后如果R[i]仍然在R[j]的前面,则称这个排序算法是稳定的,反之则称这个排序算法是不稳定的。
理解内部排序和外部排序
内部排序:数据元素是在内存中进行的排序
外部排序:数据元素太多不能同时放在内存中,而需要在排序的过程中对外存进行访问的排序过程。
常见的排序算法分为五类:
插入排序:直接插入排序和希尔排序
交换排序:冒泡排序和快速排序
选择排序:选择排序和堆排序
归并排序:归并排序
基数排序:基数排序,计数排序,桶排序
第一个排序:插入排序
基本思想:先将序列中的第1个记录看成是一个有序的子序列,然后从第2个记录起逐个进行插入,直至整个序列变成按关键字非递减有序子序列为止,整个过程进行n-1趟插入。
第i趟直接插入的操作为:当插入第i个元素时,前面i-1个序列已经排好序,第i个元素与前面元素逐个比较,找到合适的位置插入,原来位置上的元素逐个后移。
初始过程:49 38 65 97 76 13 27 49*(*特别标识这个49是序列后面的那个)
排序过程:
i=1 (38 49)65 97 76 13 27 49*
i=2 (38 49 65)97 76 13 27 49*
i=3 (38 49 65 97)76 13 27 49
i=4 (38 49 65 76 97)13 27 49
i=5 (13 38 49 65 76 97)27 49
i=6 (13 27 38 49 65 76 97)49
i=7 (13 27 38 49 49* 65 76 97)
从排序过程可以看出插入排序是一个稳定的排序算法。
最坏情况与最好情况:
最坏情况就是逆序情况
最好的情况就是正序情况
其时间复杂度在O(n)和O(n2)之间
算法代码:
//插入排序(稳定算法)
void InsertSort(int *array, int len)
{
int i, j;
int temp = 0;//记录当前插入元素
int index = 0;//记录要插入的位置
for (i = 1; i < len ; ++i)
{
index = i;
temp = array[i];
for (j = i - 1; j >= 0 && temp < array[j]; --j)
{
//如果比前一位小就将前一位元素向后挪一
array[j + 1] = array[j];
index = j;
}
//找到要插入的位置了,将其元素插入
array[index] = temp;
}
}
由于二分查找法用的比较普遍,所以再介绍一种类似的插入排序算法,折半插入排序
由于插入排序的基本操作是在一个有序表中进行查找和插入,所以这个查找的操作可以利用“折半查找”来实现
所以折半查找排序仅减少了关键字间的比较次数,而记录的移动次数不变
算法代码:
//折半插入排序
void Binary_Sort(int *array, int len)
{
int temp = 0;//用于存放要插入的元素
int mid, low,high;
int i, j;
for (i = 1; i < len; ++i)
{
low = 0, high = i - 1;
temp = array[i];//把当前插入元素赋值给temp
//进行折半查找
while (low <= high)
{
mid = (low + high) / 2;
if (temp < array[mid]) high = mid - 1;
else
low = mid + 1;
}
//挪动元素
for (j = i - 1; j >= high + 1; --j)
{
array[j + 1] = array[j];
}
//填入元素
array[high + 1] = temp;
}
}
插入排序之高级算法:希尔排序
希尔排序又称“缩小增量排序”,它也是一种属插入排序类的方法。
基本思想:先将整个待排序记录序列分割成为若干子序列分别进行直接插入排序,等整个序列“基本有序”时,再对全体记录进行一次直接插入排序。
步骤:
算法描述:
void Insert_Sort(int *array, int len, int gap)
{
int temp = 0;//记录要插入的元素
int index = 0;//记录要插入的位置
int i, j;
for (i = gap; i < len; ++i)
{
temp = array[i];
index = i;
for (j = i - gap; j >= 0 && temp < array[j]; j -= gap)
{
//挪动元素位置
array[j + gap] = array[j];
index = j;
}
//填入元素
array[index] = temp;
}
}
//希尔排序算法(不稳定算法)
void Shell_Sort(int* array, int len)
{
int gap;//增量
int j;
for (gap = len; gap > 2; gap = gap / 2)//gap=gap/2增量递减公式
{
for (j = 0; j < gap; ++j)
{
//直接插入排序
Insert_Sort(array+j,len-j,gap);
}
}
//再进行一次全排列
Insert_Sort(array,len,1);
}
需要注意的是:增量序列可以有多种取法,但应使最后一个增量必须等于1.