1. 直接插入法
思路:将一个记录插入到已排序号的有序表中。先将序列中的第一个记录看成是一个有序的子序列,然后从第二个记录其逐个进行插入,直至整个序列变成按关键字排列的有序序列。
//pArry[i]表示当前要判定的元素,将其与其前面已排序好的所有元素相比, //计算出该元素需要插入的位置j,后移pArry[j]至pArry[i - 1]元素 void InsertSort(int * pArry, int iLen) { int i, j, k, c; int temp; for (i = 1; i < iLen; i++) //指向当前需要判定的元素 { for (j = 0; j < i; j++) //与该元素之前的所有元素比较,找出该元素要插入的位置 { if (pArry[i] < pArry[j]) //pArry[i]元素应该插在pArry[j]元素所在的位置 { //保存当前要插入的值 temp = pArry[i]; //记录后移 for (k = i, c = i - j ; c > 0; c--) { pArry[k] = pArry[k - 1]; --k; } //插入到正确的位置 pArry[k] = temp; } } } }
2. 折半插入法
思路:直接插入排序法中的“查找”操作可以利用“二分查找”来实现(因为前面的子序列已经是有序序列),由此进行的插入排序称之为折半插入排序。
//pArry[i]表示当前要判定的元素,将其与其前面已排序好的所有元素相比, //计算出该元素需要插入的位置j,后移pArry[j]至pArry[i - 1]元素 void BinaryInsertSort(int * pArry, int iLen) { int i, j, k, c; int temp; for (i = 1; i < iLen; i++) //指向当前需要判定的元素 { //折半查找需要插入的位置 int low = 1; int high = i; while (low <= high) { int mid = (low + high) / 2; if (pArry[i] > pArry[mid - 1]) { low = mid + 1; } else if (pArry[i] < pArry[mid - 1]) { high = mid - 1; } else { break; } } j = (low + high) / 2; //找到需要插入的位置 temp = pArry[i]; //记录后移 for (k = i, c = i - j ; c > 0; c--) { pArry[k] = pArry[k - 1]; --k; } //插入到正确的位置, k==j pArry[k] = temp; } }
折半插入排序所需附加存储空间和直接插入排序相同,折半插入排序仅减少了关键字的比较次数,而记录的移动次数不变。因此其时间复杂度仍然为O(n^2)。
3. 希尔排序(缩小增量排序)
设待排序元素序列有n个元素,首先取一个整数dk(dk < n)作为间隔, 将全部元素分为dk个子序列,所有距离为dk的元素放在同一个子序列中,然后对每一个子序列进行直接插入排序。然后缩小间隔dk,重复上述的子序列划分和排序工作。
void ShellSort(int * pArry, int ilen) { int i, j; for (int dk = ilen / 2; dk > 0; dk /= 2) //排序趟数, dk为间隔距离 { for (i = dk; i < ilen; i++) //对子序列进行直接插入排序 { int temp = pArry[i]; for (j = i; j >= dk && temp < pArry[j - dk]; j -= dk) { pArry[j] = pArry[j - dk]; } pArry[j] = temp; } } }