基数排序

基数排序
静态基数排序
实现过程
代码
分析
链式基数排序
实现过程
代码
分析
静态基数排序
当m很大时,可以将一个记录的值即排序码拆分为多个部分来进行比较
例如:对0到9999之间的整数进行排序
1.将四位数看作是由四个排序码决定,即千,百,十,个位,其中千位为最高排序码,个位为最低排序码。基数r=10
2.可以按千百十个位数字依次进行4次桶式排序
3.4趟分配排序后,整个序列就排好序了

高位优先法:
先处理高位k d-1将序列分到若干桶中
然后再对每个桶处理次高位k d-2,分成更小的桶
依次重复,直到对k0排序后,分成最小的桶每个桶内含有相同排序码(k d-1,… , k1, k0)
最后将所有的桶中的数据依次连接在一起,成为一个有序序列
分,分,分,分,分,收

低位优先法:
从最低位k0开始排序
对于排好的序列再用次地位k1排序
依次重复,直到对最高位k d-1排好序后,整个序列成为有序的
分,收;分,收;…; 分,收的过程 比较简单,计算机常用

实现过程
下面给出一个数组
97, 53, 88, 59, 26, 41, 88, 31, 22
先对个位数进行操作:
将个位数字的个数分别统计出来
在这里插入图片描述
对之前的数进行求和
在这里插入图片描述
从原数组最后一个开始放入新数组中
在这里插入图片描述
再对十位数进行操作:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码
void RadixSort(int array[], int n, int d, int r)
{
int *Temparray = new int[n];
int *count = new int[r];
int Radix = 1;//模进位,用于取array[i]的第i位
for (int i = 0; i <= d; i++)
{//对于第i个排序码分配
for (int j = 0; j < r; j++)
{//初始计数器均为0
count[j] = 0;
}
for (int j = 0; j < n; j++)
{//统计每桶记录数
int k = (array[j] / Radix) % r;//取第i位
count[k]++;//相应计数器加1
}
for (int j = 1; j < r; j++)
{//给桶划分下标界
count[j] = count[j - 1] + count[j];
}
for (int j = n - 1; j >= 0; j–)
{//从数组尾部收集
int k = (array[j] / Radix) % r;//取第i位
count[k]–;//桶剩余量计数器减1
Temparray[count[k]] = array[j];//入桶
}
for (int j = 0; j < n; j++)
{//内容复制回array中
array[j] = Temparray[j];
}
Radix *= r;//修改模Radix
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
分析
空间代价:
临时数组,n
r个计数器
总空间代价0(n+r)

时间代价:
桶式排序:0(n+r)
d次桶式排序
0(d * (n + r))

链式基数排序
实现过程
下面给出一个数组
97, 53, 88, 59, 26, 41, 88, 31, 22
第一步,构建相应的链表,以末尾数字作为排序依据
在这里插入图片描述
接下来整理到数组里
在这里插入图片描述
第二步,再一次构建相应的链表
在这里插入图片描述
在这里插入图片描述

代码
struct Node
{//节点类
public:
int key;//节点对关键码值
int next;//下一节点在数组中的下标
};

class StaticQueue
{//静态队列类
public:
int head;
int tail;
};

void Distribute(Node *array, int first, int i, int r, StaticQueue *queue)
{
for (int j = 0; j < r; j++)
{
queue[j].head = -1;
}
int curr = first;
while (curr != -1)
{//对整个静态链进行分配
int k = array[curr].key;
for (int a = 0; a < i; a++)
{//取第i位排序码数字k
k = k / r;
}
k = k % r;
if (queue[k].head == -1)
{//把数据分配到第k个桶中
queue[k].head = curr;
}
else
{
array[queue[k].tail].next = curr;
}
queue[k].tail = curr;
curr = array[curr].next;//curr移动,继续分配
}
}

void Collect(Node *array, int &first, int r, StaticQueue *queue)
{
int k = 0;//已收集到的最后一个记录
while (queue[k].head == -1)
{//找到第一个非空队
k++;
}
first = queue[k].head;
int last = queue[k].tail;
while (k < r - 1)
{//继续收集下一个非空队列
k++;
while (k < r - 1 && queue[k].head == -1)
{
k++;
}
if (queue[k].head != -1)
{//试探下一个队列
array[last].next = queue[k].head;
last = queue[k].tail;//最后一个为序列的尾部
}
}
array[last].next = -1;//收集完毕
}

void AddrSort(Node *array, int n, int first)
{
int j = first;//j待处理数据下标
Node TempRec;
for (int i = 0; i < n - 1; i++)
{//循环,每次处理第i个记录
TempRec = array[j];//暂存第i个的记录array[j]
swap(array[i], array[j]);
array[i].next = j;//next链要保留调换轨迹j
j = TempRec.next;//j移动到下一位
while (j <= i)
{//j比i小,则是轨迹,顺链找
j = array[j].next;
}
}
}

void RadixSort(Node *array, int n, int d, int r)
{
int first = 0;//first指向第一个记录
StaticQueue *queue = new StaticQueue[r];
for (int i = 0; i < n - 1; i++)
{//初始化静态指针域
array[i].next = i + 1;
}
array[n - 1].next = -1;//链尾next为空
//对第i个排序码进行分配和收集,一共d趟
for (int i = 0; i < d; i++)
{
Distribute(array, first, i, r, queue);
Collect(array, first, r, queue);
}
delete[]queue;
AddrSort(array, n, first);//整理后,按下标有序
for (int i = 0; i < 9; i++)
{
cout << array[i].key << endl;
}
}

int main()
{
Node array[9];
array[0].key = 97;
array[1].key = 53;
array[2].key = 88;
array[3].key = 59;
array[4].key = 26;
array[5].key = 41;
array[6].key = 88;
array[7].key = 31;
array[8].key = 22;
RadixSort(array, 9, 2, 10);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
分析
空间代价:
n个记录空间
r个子序列的头尾指针
0(n + r)

时间代价:
不需要移动记录本身,只需要修改记录的next指针
0(d * (n + r))
时间代价为0(d * n),实际上还是0(n * log(n))
没有重复关键码的情况,需要n个不同的编码来表示它们,也就是说,d >= log r(n),即在 log n中。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值