前三篇文章:
排序算法总结(2)——选择排序
排序算法总结(1)——插入排序
四、归并排序
归并排序和快速排序一样,是使用分治策略实现的排序算法,算法可以采用递归实现。所谓归并,就是将两个或两个以上的有序数据序列合并成一个新的有序数据序列。
假设数组Array有N个元素,那么可以看成数组Array是由N个有序的子序列组成,每个子序列的长度为1,然后再两两合并,得到了一个N/2个长度为2或1的有序子序列,再两两合并,如此重复,直到得到一个长度为N的有序数据序列为止,利用两个有序序列的合并来实现归并排序的排序方法,称为二路归并排序。
可以用迭代的思路写代码:
void Merge(int *a, int n, int *temp, int k)
{
//k为有序数组的长度
//一次二路归并排序后的有序子序列存于数组temp中
int head1 = 0;//前一个数组的起始位置
int head2, tail1, tail2;//分别表示第一个 第二个有序自序列的头尾
int i,j,nTemp = 0;
while (head1 + k < n-1)
{
head2 = head1 + k;//第二个自序列的起始位置
tail1 = head2 - 1;//第一个自序列的末尾
tail2 = (head2+k-1 <= n - 1) ? (head2+k-1) : n-1;//第二个自序列的末尾
//两个有序自序列的归并
for (i = head1, j = head2; i <= tail1 && j <= tail2; nTemp ++)
{
if (a[i] <= a[j])
{
temp[nTemp] = a[i];
i ++;
}
else
{
temp[nTemp] = a[j];
j ++;
}
}
//自序列2归并完,将自序列1放到临时数组的后面
while (i <= tail1)
{
temp[nTemp] = a[i];
i ++;
nTemp ++;
}
//自序列1归并完,将自序列2放到临时数组的后面
while (j <= tail2)
{
temp[nTemp] = a[j];
j ++;
nTemp ++;
}
head1 = tail2 + 1;
}
//只够一组的数据元素放到临时数组中
for (i = head1; i < n; i ++, nTemp++)
temp[nTemp] = a[i];
}
void MergeSort(int *a, int n)
{
int i,k=1;//k表示归并长度从1开始
int *temp;
temp = (int *)malloc(n*sizeof(int));//动态申请临时数组空间
while (k<n)
{
Merge(a,n,temp,k);//调用归并函数
for (i = 0; i < n; i++)
a[i] = temp[i];//元素从临时数组放回原数组
k = 2 * k;//归并长度加倍
}
free(temp);
}
五、基数排序
基数排序算法的基本思想是:设待排序的数据元素关键字是m位d进制整数(不足m位的关键字在高位补0),设置d个桶,令其编号分别为0,1,2,...,d-1。首先,按关键字最低位的数值依次把各数据元素放到相应的桶中;然后,按照桶号从小到大和进人桶中数据元素的先后次序收集分配在各桶中的数据元素;这样,就形成了数据元素集合的一个新的排列,称这样的一次排序过程为一次基数排序。再对一次基数排序得到的数据元素序列按关键字次低位的数值依次把各数据元素放到相应的桶中,然后按照桶号从小到大和进人桶中数据元素的先后次序收集分配在各桶中的数据元素。这样的过程重复进行,当完成了第m次基数排序后,就得到了排好序的数据元素序列。
下图是一个排序{710,342,045,686,006,841,429,134,068,264}的例子.
链式队列是实现基数排序常用的方法。
在基于链式队列的基数排序算法中,可以把d个队列设计成一个队列数组(设队列数组名为tub),队列数组的每个元素中包括两个域:front域和rear域。front域用于指示队头,rear域用于指示队尾。当第 i ( i = 0,1,2,..,d一1)个队列中有数据元素要放入时,就在队列数组的相应元素tub[i]中的队尾位置插人一个结点。基于链式队列基数排序算法的存储结构示意图如图所示。
代码省略。
六、性能比较