什么是基数排序?
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
基数排序的图解
看以上的官方解释,我个人是觉得比较头大的。
所以,以下直接介绍其具体的图解,以便于理解。
具体的代码实现
#include <stdio.h>
#include "Queue.h"
//Digit表示的是数据的最高位数
//Radix表示的是基数的个数,也就是数据的个数
#define Digit 3
#define Radix 10
//GetKey函数是用来获取val的第k位那个数据
//这里表示从个位向高位依次取
//主要作用是为了方便根据其返回值将其分配到相应创建的队列中去。
int GetKey(int val, int k) {
int key = 0;
while (k >= 0) {
key = val % 10;
val /= 10;
k--;
}
return key;
}
//基数排序函数
void RadixSort(int arr[], int left, int right) {
Queue Q1;
QueueInit(&Q1);
Queue Q2;
QueueInit(&Q2);
Queue Q3;
QueueInit(&Q3);
Queue Q4;
QueueInit(&Q4);
Queue Q5;
QueueInit(&Q5);
Queue Q6;
QueueInit(&Q6);
Queue Q7;
QueueInit(&Q7);
Queue Q8;
QueueInit(&Q8);
Queue Q9;
QueueInit(&Q9);
//先根据其最高位的位数来进行相应次外部大循环
for (int i = 0; i < Digit; i++) {
//分配
//根据GetKey的返回值,将数组中的数据分配进相应创建的队列中去。
for (int j = left; j < right; j++) {
int key = GetKey(arr[j], i);
if (key == 1) {
QueuePush(&Q1, arr[j]);
}
if (key == 2) {
QueuePush(&Q2, arr[j]);
}
if (key == 3) {
QueuePush(&Q3, arr[j]);
}
if (key == 4) {
QueuePush(&Q4, arr[j]);
}
if (key == 5) {
QueuePush(&Q5, arr[j]);
}
if (key == 6) {
QueuePush(&Q6, arr[j]);
}
if (key == 7) {
QueuePush(&Q7, arr[j]);
}
if (key == 8) {
QueuePush(&Q8, arr[j]);
}
if (key == 9) {
QueuePush(&Q9, arr[j]);
}
}
//归并
//将分配好的值一一从队列中分别取出,放入原来的数组中去。
int z = 0;
for (int i = 1; i <= Radix; i++) {
if (i == 1) {
while(!QueueEmpty(&Q1)) {
arr[z++] = QueueFront(&Q1);
QueuePop(&Q1);
}
}
if (i == 2) {
while (!QueueEmpty(&Q2)) {
arr[z++] = QueueFront(&Q2);
QueuePop(&Q2);
}
}
if (i == 3) {
while (!QueueEmpty(&Q3)) {
arr[z++] = QueueFront(&Q3);
QueuePop(&Q3);
}
}
if (i == 4) {
while (!QueueEmpty(&Q4)) {
arr[z++] = QueueFront(&Q4);
QueuePop(&Q4);
}
}
if (i == 5) {
while (!QueueEmpty(&Q5)) {
arr[z++] = QueueFront(&Q5);
QueuePop(&Q5);
}
}
if (i == 6) {
while (!QueueEmpty(&Q6)) {
arr[z++] = QueueFront(&Q6);
QueuePop(&Q6);
}
}
if (i == 7) {
while (!QueueEmpty(&Q7)) {
arr[z++] = QueueFront(&Q7);
QueuePop(&Q7);
}
}
if (i == 8) {
while (!QueueEmpty(&Q8)) {
arr[z++] = QueueFront(&Q8);
QueuePop(&Q8);
}
}
if (i == 9) {
while (!QueueEmpty(&Q9)) {
arr[z++] = QueueFront(&Q9);
QueuePop(&Q9);
}
}
}
}
QueueDestory(&Q1);
QueueDestory(&Q2);
QueueDestory(&Q3);
QueueDestory(&Q4);
QueueDestory(&Q5);
QueueDestory(&Q6);
QueueDestory(&Q7);
QueueDestory(&Q8);
QueueDestory(&Q9);
}
int main() {
int arr[] = {258,132,996,658,359,159,652,111,225,296 };
int k = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < k; i++) {
printf("%d ", arr[i]);
}
printf("\n");
RadixSort(arr, 0, k);
for (int i = 0; i < k; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
Queue.h代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <time.h>
//前置声明
typedef int QDataType;
typedef struct QueueNode {//队列的定义,用指针来创建
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue {//直接另外建立两个指针用来指向队列的队头和队尾。
//方便了很多,比如头插和头删,以及查找队头和队尾元素都方便多了
//减少了遍历次数
QNode* head;
QNode* tail;
}Queue;
//队列的初始化
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestory(Queue* pq);
//队列的加数据(只能尾插)
void QueuePush(Queue* pq, QDataType x);
//队列的删数据(只能头删)
void QueuePop(Queue* pq);
//找队头的节点
QDataType QueueFront(Queue* pq);
//找队尾的节点
QDataType QueueBack(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
//计算队列的节点个数
int QueueSize(Queue* pq);
Queue.c代码
#include "Queue.h"
void QueueInit(Queue* pq) {
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
void QueueDestory(Queue* pq) {
assert(pq);
QNode* cur = pq->head;
while (cur) {
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
void QueuePush(Queue* pq,QDataType x) {
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));//创建新节点,准备插入
if (newnode == NULL) {
printf("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL) {//当队列为空
pq->tail = pq->head = newnode;
}
else {//当队列不为空
pq->tail->next = newnode;
pq->tail = newnode;
}
}
void QueuePop(Queue* pq) {
assert(pq);
assert(!QueueEmpty(pq));//为空的时候不能再删除了
//只有一个节点的
if (pq->head->next == NULL) {
free(pq->head);
pq->head = NULL;
pq->tail = NULL;
}
else {//有多个节点的
QNode* tmp = pq->head->next;
free(pq->head);
pq->head = tmp;
}
}
QDataType QueueFront(Queue* pq) {
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Queue* pq) {
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
bool QueueEmpty(Queue* pq) {
assert(pq);
return (pq->head == NULL);//为空的话那么tail和head
//至少有一个为空,head或者tail都可以
}
int QueueSize(Queue* pq) {
assert(pq);
QNode* cur = pq->head;
int size = 0;
while (cur) {
++size;
cur = cur->next;
}
return size;
}