1. 归并排序
a. 基本思想
”归并”的含义是将两个或两个以上的有序表归并组合成一个新的有序表。例如: 待排序表含有n个记录,则可以看成是n个有序的子表,每个子表长度为1,然后两两归并,得到[n/2]个长度为2或1(遗留的1); 再两两归并。。。如此重复直到合并成一个长度为n的有序表为止。2-路归并排序。当然还有3路,4路。。。等
b. 代码
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType)); //辅助数组B
void Merge(ElemType A[], int low, int mid, int high){
//表A的两段A[low....mid]和A[mid+1......high]各自有序,将它们合并成一个有序表
for(int k=low;k<=high;k++)
B[k]=A[k]; //将A中2段区域的元素复制到B中
for(i=low,j=mid+1,k=i;i<=mid&&j<high;k++){
if(B[i]<=B[j]) //比较B的左右两段中的元素
A[k]=B[i++]; //将较小值复制到A中
else
A[k]=B[i++];
}//for
while(i<=mid) A[k++]=B[i++]; //若第一个表未检测完,复制
while(j<=high) A[k++]=B[j++]; //若第二个表未检测完,复制。2个只会有一个检测完
}
void MergeSort(ElemType A[], int low, int high){
if(low<high){
int mid = (low+high)/2; //中间划分2个子序列.(适用2路归并,)
MergeSort(A,low,mid); //对左侧子序列进行递归排序
MergeSort(A,mid+1,high); //对右侧子序列进行递归排序
Merge(A,low,mid,high); //归并
}//if
}
c. 性能分析
空间复杂度:O(n)
时间复杂度:O(nlogn)
稳定性:Merge()操作不会改变相同关键字记录的相对次序,所以2路归并是稳定的。
2. 基数排序
a. 基本思路
采用多关键字排序思想(即基于关键字个位的大小进行排序),借助“分配”和“收集”两种操作对单逻辑关键字进行排序。基数排序又分为最高位优先(MSD)排序和最低位优先(LSD)排序
b. 实现过程
1). 假设线性表由节点序列a0,a1,a2,…..,an-1构成,每个节点的关键字由d元组组成。在排序过程中,使用r个队列Q0,Q1,Q2,……,Qr-1。排序如下:(对i=0,1,2,…..,d-1,依次做一次“分配”和“收集”。就是一次稳定的排序过程)
2). 分配:开始时,把Q0, Q1, ….. , Qr-1各个队列置成空队列,然后考察线性表中的每一个结点aj(j=0,1, ….. ,n-1),如果aj的关键字kj=k,就把aj放入Qk队列中
3). 收集:把Q0,Q1,…..,Qr-1各个队列中的节点依次首尾相接,得到新的结点序列,从而组成新的线性表。
其实应该是0,1,…,9依次排开说明更好。有个更好的图解https://blog.youkuaiyun.com/qq_35820702/article/details/52975231
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
//初始化一个队列
LINK_SORT *init_queue()
{
LINK_SORT *p = (LINK_SORT *)malloc(sizeof(LINK_SORT));
assert(p != NULL);
p->data = 0;
p->next = NULL;
return p;
}
//销毁队列
bool destory_queue(LINK_SORT *phead)
{
if (phead == NULL)
{
return false;
}
LINK_SORT *p = phead->next;
//释放队列中的元素
while (p != NULL)
{
phead->next = p->next;
free(p);
p = phead->next;
}
free(phead); //释放头结点
return true;
}
//申请一个结点
static LINK_SORT *alloc_node(elem_type e)
{
LINK_SORT *tmp = (LINK_SORT *)malloc(sizeof(LINK_SORT));
assert(tmp != NULL);
tmp->data = e;
tmp->next = NULL;
return tmp;
}
//判断队列是否为空
bool is_empty(LINK_SORT *phead)
{
if (phead == NULL)
{
return false;
}
return phead->next == NULL;
}
//查看队列中的第一个元素,只是查看,并不出队列
bool get_head(LINK_SORT *phead, elem_type *e)
{
if (phead == NULL)
{
return false;
}
*e = phead->next->data;
return true;
}
//入队列
bool push(LINK_SORT *phead, elem_type e)
{
if (phead == NULL)
{
return false;
}
LINK_SORT *p = phead;
LINK_SORT *tmp = alloc_node(e);
while(p->next != NULL)
{
p = p->next;
}
p->next = tmp;
return true;
}
//出队列
bool pop(LINK_SORT *phead, elem_type *e)
{
if (phead == NULL || is_empty(phead))
{
return false;
}
LINK_SORT *p = phead->next;
phead->next = p->next;
*e = p->data;
free(p);
return true;
}
//计算数组中最大元素的位数
int get_base(int *arr,int len)
{
int max = arr[0];
//求数组中的最大元素
for (int i=1;i<len;i++)
{
if (max < arr[i])
{
max = arr[i];
}
}
int count = 0;
// 计算最大元素的位数
while(max != 0)
{
max /= 10;
count++;
}
return count;
}
//排序
void base_sort(int *arr, int len, int base,int radix)
{
LINK_SORT **bucket = (LINK_SORT **)malloc(sizeof(LINK_SORT *) * radix);//二级指针用来保存队列的地址
assert(bucket != NULL);
for (int i = 0;i<len;i++)
{
bucket[i] = init_queue();//以待排序数组的长度为标准初始化队列
}
for (int i = 0;i<base;i++)//遍历每个元素的每一位
{
for (int j = 0;j<len;j++)
{
//将数组中的元素逐一放进它第base位所对应的队列中
push(bucket[(arr[j]/(int)pow((double)radix,i))%radix],arr[j]);
}
int k = 0;
for (int j = 0;j<len;j++)
{
while(!is_empty(bucket[j]))//当队列不为空时,出队列,并继续放到数组中
{
pop(bucket[j],&arr[k]);
k++;
}
}
}
for (int i = 0;i<len;i++)
{
destory_queue(bucket[i]);
}
free(bucket);
}
int main()
{
int arr[] = {278,109,63,930,589,184,505,269,8,83};
int len = sizeof(arr)/sizeof(arr[0]);
int base = get_base(arr,len);
int radix = 10;
base_sort(arr, len, base,radix);
for (int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
return 0;
}
c. 性能分析
空间效率O(r)。r个队列用来排序
时间复杂度: d趟分配和收集,分配O(n),收集O(r)。O(d(n+r))
稳定性:是稳定的