一、直接插入排序
1.1 算法思想
完整的直接插入排序是从 i=2 开始的,即将第一个记录视为已排好序的单元素子集合,然后将第二个记录插入单元素子集合中。i 从2循环到n,即可实现完整的直接插入排序。
绿色部分为已排好序的记录
监视哨的作用:
1、备份待插入的记录,以便前面关键字较大的记录后移;
2、防止越界。
1.2 算法实现
void InsSort(RecordType r[], int n) {
int i, j;
for (i = 2; i <= n; ++i) {
/* 将待插元素放入暂存单元r[0] */
r[0] = r[i];
j = i - 1;
/* 寻找插入位置 */
while (r[0].key < r[j].key) {
r[j + 1] = r[j];
--j;
}
/* 插入待插元素 */
r[j + 1] = r[0];
}
}
算法要点:
1、使用监视哨r[0]临时保存待插入的记录;
2、从后往前查找应插入的位置;
3、在同一循环中完成查找和移动。
1.3 算法性能分析
二、折半插入排序
2.1 算法思想
与直接插入排序的区别在于: 查找插入位置时使用的方法不同。
2.2 算法实现
void BinSort(RecordType r[], int n) {
int i, j;
int low, high, mid;
for (i = 2; i <= n; ++i) {
/* 将待插元素放入暂存单元r[0] */
r[0] = r[i];
/* 折半查找法,确定插入位置 */
low = 1; high = i - 1;
while (low <= high) {
mid = (low + high) / 2;
if (r[0].key < r[mid].key)
high = mid - 1;
else
low = mid + 1;
}
/* 腾出插入位置 */
for (j = i - 1; j >= low; --j)
r[j + 1] = r[j];
r[j + 1] = r[0];
}
}
算法要点:
1、使用监视哨r[0]临时保存待插入的记录;
2、使用折半查找法查找应插入的位置;
3、查找完成后,再完成移动。
2.3 算法性能分析
三、希尔排序
3.1 算法思想
基本思想:将整个待排序记录分割成若干个子序列,在子序列内分别进行直接插入排序,待整个序列中的记录基本有序时,对全体记录进行直接插入排序。
颜色相同的记录组成一个子序列
3.2 算法实现
void ShellInsert(RecordType r[], int n) {
int i, j, d;
/* 逐渐缩短步长,直至步长为1 */
for (d = n/2; d >= 1; d = d/2) {
/* 对各个子序列进行直接插入排序 */
for (i = 1 + d; i <= n; ++i) {
r[0] = r[i]; j = i - d;
while (j > 0 && r[0].key < r[j].key) {
r[j + d] = r[j];
j -= d;
}
r[j + d] = r[0];
}
}
}
说明:for (i = 1 + d; i <= n; ++i) 循环是穿插着完成所有子序列的直接插入排序的。
处理顺序:
1. 处理第一个子序列的第二个记录;
2. 处理第二个子序列的第二个记录;
……
d. 处理第d个子序列的第二个记录;
1. 处理第一个子序列的第三个记录;
2. 处理第二个子序列的第三个记录;
……
d. 处理第d个子序列的第三个记录;
……
直至处理完所有的记录。