归并排序
- 基本思想 归并排序采用分而治之的思想,将数组递归的划分成小的子表,再逐趟的将个子表排序后归并成一个新的有序表。
- 时间复杂度 每趟归并的时间复杂度是O(n),共需进行log(n)趟,所以时间复杂度是nlog(n)
- 空间复杂度 O(n)
- 稳定性 归并排序是稳定的排序算法
代码实现
void merge(int *a, int low, int mid, int high){
int i = 0, j = 0, k = low;
int llen = mid - low + 1;
int rlen = high - (mid + 1) + 1;
int len = high - low + 1;
int b[len]; //辅助空间
//将元素赋值到辅助数组
for(m = 0; m < len; m ++){
b[m] = a[low + m];
}
while(i < llen && j < rlen){
if(b[i] <= b[j + mid + 1 - low]){
a[k] = b[i++];
else{
a[k] = b[(j++) + mid + 1 - low];
}
k ++;
}
while(i < llen) a[k++] = b[i ++];
while(j < rlen) a[k++] = b[(j ++) + mid + 1 - low];
}
// 哨兵版
void merge(int *a, int low, int mid, int high){
int i = 0, j = 0, k = low;
int llen = mid - low + 1;
int rlen = high - (mid + 1) + 1;
//辅助空间,对分配的一个元素存放哨兵
int larr[llen + 1];
int rarr[rlen + 1];
//将元素复制到辅助空间
for(i = 0; i < llen; i ++) larr[i] = a[i + low];
for(j = 0; j < rlen; j ++) rarr[j] = a[j + mid + 1 - low];
//哨兵就位
larr[llen] = rarr[rlen] = INT_MAX;
i = 0, j = 0;
while(larr[i] != INT_MAX){
if(larr[i] <= rarr[j]){
a[k] = larr[i ++];
}else{
a[k] = rarr[j++];
}
k ++;
}
}
// 合并操作
void mergeSort(int *a, int low, int high){
if(low >= high) return;
mid = low + ((high - low) >> 1);
mergeSort(a, low, mid);
mergeSort(a, mid + 1, high);
merge(a, low, mid, high);
}
基数排序
使用LSD的情况下,基数排序通常是是稳定的非比较排序
- 时间复杂度 d(n + rd)
- 空间复杂度 r r表示基数,比如,当基数为0-9时,r为10
链式基数排序
基于静态链表的数据结构
#include <stdio.h>
#define MAX_KEY_NUM 8
#define MAX_SPACE 100
#define RADIX 10
#define ord(c) ((c) - ('0'))
typedef char keyType;
typedef int ArrType[RADIX]; //指针数组
typedef struct {
keyType keys[MAX_KEY_NUM];
int next;
}SLCell;
typedef struct {
SLCell elem[MAX_SPACE];
int keyNum;
int num;
}SLList;
//分配
void distribute(SLList* sl, int i, ArrType f, ArrType e) {
int j, p = 0;
//将辅助数组置0
for (int i = 0; i < RADIX; i++) {
f[i] = e[i] = 0;
}
while (p = (*sl).elem[p].next) {
j = ord((*sl).elem[p].keys[i]); //将数字字符映射到[0....RADIX - 1]
if (!f[j])
f[j] = p; //指向链表首结点
else
(*sl).elem[e[j]].next = p;
e[j] = p; //e[j] 指向链表末结点
}
}
void collect(SLList* sl, ArrType f, ArrType e) {
int i = 0, tail;
while (i < RADIX && f[i] == 0) i++;
if (i < RADIX) {
(*sl).elem[0].next = f[i];
tail = e[i];
while (i < RADIX) {
i++;
while (i < RADIX && f[i] == 0) i++; //找到下一个非空子表
if (i < RADIX) { //链接两个非空子表
(*sl).elem[tail].next = f[i];
tail = e[i];
}
}
}
(*sl).elem[tail].next = 0; //保持循环链表
}
//基数排序
void radixSort(SLList* sl) {
ArrType f, e;
for (int i = (*sl).keyNum - 1; i >= 0; i--) {
distribute(sl, i, f, e);
collect(sl, f, e);
}
}
void traverse(SLList* sl) {
int p = 0;
while (p = (*sl).elem[p].next) {
for (int i = 0; i < (*sl).keyNum; i++) {
printf("%c", (*sl).elem[p].keys[i]);
}
printf("\n");
}
}
int main() { //测试方法写的不够严谨,仅供测试
int k = 0, c = 1;
SLList sl;
int keyNum = 3;
char str[] = "278,109,063,930,589,184,505,269,008,083";
int i = 0;
while (str[i] != '\0') {
k = 0;
while (str[i] != ',' && str[i] != '\0') {
sl.elem[c].keys[k++] = str[i++];
}
if (str[i] == ',') {
c++;
i++;
}
}
sl.keyNum = keyNum;
sl.num = c;
for (k = 0; k < c; k++) { //链接结点
sl.elem[k].next = k + 1;
};
sl.elem[k].next = 0; //设置为循环链表
radixSort(&sl);
traverse(&sl);
return 0;
}