有时我们需要对多关键字数据进行排序,如扑克牌有花色和数字两个关键字,如果我们对扑克牌排序,假设四种花色为A、B、C、D,要求花色优先级高于数字,有两种方法
1.先按花色分成4堆,然后对每一堆排好序后,将4堆牌按次序放在一起,这种方法是最高位优先法MSD
2.先按数字分成13堆,然后将它们按次序叠在一起,如13在上,1在下,然后再一张一张的按花色分成四堆,因为此时牌已经按照数字牌好了,因此按花色分配时,后来被分配的牌的数字一定比已经分配的小,最终再将4堆牌按次序放在一起,完成排序,这种方法是最低位优先法
可以看出,按MSD排序时,是分成了一个个子序列,对每个子序列排序时可以选各种稳定或不稳定的排序方法
按LSD排序时,每次排序时都是一整个序列,对整个序列按某个关键字排序时,需要采用稳定的排序方法,不然可能第2个关键字排好了,第一个又乱了
桶排序就是一种MSD排序方式,先将数据按照一定范围分为多组,再对每一组进行排序,最后合并
基数排序是一种LSD排序方式,基数指的是关键字的取值范围,如果十进制数进行排序,基数就是10。
最开始基数排序需要基数d*数据长度n
的辅助空间,后来用计数
代替分配的方式来优化空间使用,此时需要使用d+n
的辅助空间,后来提出了链式基础排序,采用链表结构,辅助空间仅需要2*d
#include
#include
#include
#define ARRAY_SIZE 9
void radixSort(int *arr, int size)
{
int max = 0;
int min = 0;
int base = 0;
int i = 0;
int bucket[10] = {0};
int *sortedArr = NULL;
int index = 0;
if (!arr)
{
return;
}
/* 保存每次排序完的数据 */
sortedArr = (int *)malloc(sizeof(int) * size);
if (!sortedArr)
{
return;
}
memset(sortedArr, 0, sizeof(int) * size);
/* 如果有负数,先转成正数 */
max = arr[i];
min = arr[i];
for (i = 0; i < size; i++)
{
max = max > arr[i] ? max : arr[i];
min = min < arr[i] ? min : arr[i];
}
if (min < 0)
{
for (i = 0; i < size; i++)
{
arr[i] -= min;
}
}
max -= min;
base = 1;
/* max是最大的数,也是最长的数,通过类
* 似二进制右移动的原理来计算位数 */
while (max / base)
{
/* 每次都要先清零,防止上次数据参与进来 */
memset(bucket, 0, sizeof(int) * 10);
/* 每次对单个数字进行计数排序 */
for (i = 0; i < size; i++)
{
bucket[(arr[i] / base) % 10]++;
}
for (i = 1; i < 10; i++)
{
bucket[i] += bucket[i - 1];
}
for (i = size - 1; i >=0; i--)
{
index = bucket[(arr[i] / base) % 10];
sortedArr[index - 1] = arr[i];
bucket[(arr[i] / base) % 10]--;
}
for (i = 0; i < size; i++)
{
arr[i] = sortedArr[i];
}
base *= 10;
}
/* 还原数据 */
if (min < 0)
{
for (i = 0; i < size; i++)
{
arr[i] += min;
}
}
free(sortedArr);
}
int main(void)
{
int i = 0;
int array[ARRAY_SIZE] = {38, 22, -3, 1, 29, 4, 58, 352, 6};
radixSort(array, ARRAY_SIZE);
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%d ", array[i]);
}
puts("");
return 0;
}
#include
#include
#include
#define ARRAY_SIZE 9
struct listNode
{
int val;
struct listNode *next;
};
/* 分配 */
void distribute(struct listNode *head, int base, struct listNode **radixHead, struct listNode **radixTail)
{
int index = 0;
struct listNode *curNode = NULL;
if (!head || !radixHead || !radixTail)
{
return;
}
curNode = head;
while (curNode)
{
index = (curNode->val / base) % 10;
if (!radixHead[index])
{
radixHead[index] = radixTail[index] = curNode;
}
else
{
/* 尾插法,稳定排序 */
(radixTail[index])->next = curNode;
radixTail[index] = curNode;
}
curNode = curNode->next;
}
}
struct listNode *collect(struct listNode **radixHead, struct listNode **radixTail)
{
struct listNode *head = NULL;
int i = 0;
int j = 0;
if (!radixHead || !radixTail)
{
return NULL;
}
for (i = 0; i < 10; i++)
{
if (radixHead[i])
{
head = radixHead[i];
(radixTail[i])->next = NULL;
break;
}
}
for (j = i + 1; j < 10; j++)
{
if (radixHead[j])
{
(radixTail[i])->next = radixHead[j];
/* 不要忘了将最后一个置为空指针 */
(radixTail[j])->next = NULL;
i = j;
}
}
return head;
}
struct listNode *radixSort(struct listNode *head)
{
int min = 0;
int max = 0;
int base = 0;
struct listNode *curNode = NULL;
/* 每个基数链表的头指针 */
struct listNode *radixHead[10] = {NULL};
/* 每个基数链表的尾指针 */
struct listNode *radixTail[10] = {NULL};
if (!head)
{
return NULL;
}
curNode = head;
min = max = curNode->val;
while (curNode)
{
min = min < curNode->val ? min : curNode->val;
max = max > curNode->val ? max : curNode->val;
curNode = curNode->next;
}
if (min < 0)
{
curNode = head;
while (curNode)
{
curNode->val -= min;
curNode = curNode->next;
}
max -= min;
}
base = 1;
while (max / base)
{
memset(radixHead, 0, sizeof(struct listNode *) * 10);
memset(radixTail, 0, sizeof(struct listNode *) * 10);
distribute(head, base, radixHead, radixTail);
head = collect(radixHead, radixTail);
base *= 10;
}
if (min < 0)
{
curNode = head;
while (curNode)
{
curNode->val += min;
curNode = curNode->next;
}
}
return head;
}
int main(void)
{
int i = 0;
int array[ARRAY_SIZE] = {38, 22, 3, 1, 29, 4, 58, 52, 6};
struct listNode *list = NULL;
list = (struct listNode *)malloc(sizeof(struct listNode) * ARRAY_SIZE);
if (!list)
{
return 0;
}
memset(list, 0, sizeof(struct listNode) * ARRAY_SIZE);
for (i = 0; i < ARRAY_SIZE; i++)
{
list[i].val = array[i];
if (i != (ARRAY_SIZE - 1))
{
list[i].next = list + i + 1;
}
}
list = radixSort(list);
// for (i = 0; i < ARRAY_SIZE; i++)
while (list)
{
printf("%d ", list->val);
list = list->next;
}
puts("");
return 0;
}
O(n)
取决于数据范围
有负数需要先处理一下