表排序
又称间接排序,排序时不调整元素的实际位置,而是定义一个额外的数组作为“表”(table)。根据元素的关键字大小来调整元素对应下标在表中的位置。
例
初始
A | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] |
---|---|---|---|---|---|---|---|---|
key | f | d | c | a | g | b | h | e |
table | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
初始的一个结构体数组,需要根据key的大小来进行排序,但是这里只调整table中下标的位置。表排序在调整下标的位置时可以使用其他的排序算法,例如直接插入排序。
调整后
A | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] |
---|---|---|---|---|---|---|---|---|
key | f | d | c | a | g | b | h | e |
table | 3 | 5 | 2 | 1 | 7 | 0 | 4 | 6 |
如果仅要求按顺序输出,则输出:
物理排序
经过表排序后,得到了排好序的table数组,但是如果需要调整元素的实际位置,那就需要物理排序。
实现
- N个数字的排序由若干个独立的环组成
- 在每个环中进行元素实际位置的交换
- 使用
temp
来保存第一个元素 - 把
A[table[i]]
的元素放置于i
,同时修改table[i] = i
- 如果
table[i] == i
说明环结束,并把temp置于这个位置
- 使用
struct Element {
ElementType Data; // data可以是任意类型
ElementType key; // 关键字只要可比即可
}
// 物理排序过程 Elements = 元素数组, table = 表数组,假设表数组已经排好了
void Sort(Element[] Elements, int[] table, int N) {
for (i = 0; i < N; i++) {
Temp = Elements[i];
int j = i;
while (table[j] != j) {
Elements[j] = Elements[table[j]]; // 把实际该置于j位置的元素置于J
NextIndex = table[j]; // 记录下一个元素的位置
table[j] = j;
j = NextIndex; // 让j跳到下一个元素
}
if (Elements[j] != Temp) { // 说明该环不止一个元素,需要进行temp的赋值
Elements[j] = Temp;
}
}
}
复杂度分析
- 最好情况:初始即有序
- 最坏情况:
- 有
⌊N/2⌋ 个环,每个环包含2 个元素 - 需要
⌊3N/2⌋ 次元素移动
- 有
T=O(mN) ,m是每个元素复制的时间