直接插入排序的基本操作是将一个记录插入到已经排序好的有序表中(最开始假设第一个数为已排序),从而得到一个新的、记录数增1的有序表。
稳定性:直接插入排序是稳定排序
复杂度: 最好: O(n) 最差: O(n^2) 平均: O(n^2)
辅助空间:O(1)
下面是根据书上用L[0]存储哨兵位置而写的直接插入排序,由于书是对于顺序表进行排序,而我此处仅仅是数组,且要传参数n,故给定n值只能排序数组的后n-1个数(即序号为1~n-1的数)。 给定代码是为了和下面的对n个数的排序进行一个对照而已。
/* 直接插入排序更适合从1开始的数组(或者说下面这个程序0位置必须不用于存储数据)*/ /* n传值n但只能排序后n-1个数*/ void InsertSort1(int *L, int n){ int i, j; for (i = 1; i < n - 1; ++i){ //i表示已经有序的序列的最后一个下标 if (L[i + 1] < L[i]){ //已经有序序列的下一位找到更小的,需要插入 L[0] = L[i + 1]; //设置哨兵,正是由于这里用到了L[0] for (j = i; L[j] > L[0]; --j){ L[j + 1] = L[j]; //比哨兵值大的都往后移(或者这一直移动到L[0]) } //此时j的数小于哨兵或j位于L[0] L[j + 1] = L[0]; //哨兵插入正确位置 }//if }//for(i) }
接下来是自己写的给定数组和元素个数n,对n个数进行排序的数组实现,可用于和上面对照。
/*直接插入排序 --- 数组法(且给定n就排序n个数)*/ void InsertSort2(int *L, int n){ int i, j, tmp; for (i = 0; i < n - 1; ++i){ //i为已排序序列的最大值下标 if (L[i + 1] < L[i]){ //后面的数小于已排序的序列,需要插入 tmp = L[i + 1]; //设置哨兵值 //利用&&运算符的短路特性可防止数组越界(即避免访问L[-1]) for (j = i; j >= 0 && L[j] > tmp; --j){ L[j + 1] = L[j]; }//for(j) //结束后j为-1或比哨兵值小地数的位置 L[j + 1] = tmp; } }//for(i) }
加下来是直接插入排序的指针实现:
/* 直接插入排序 --- 指针实现 */ /* [head,tail)为左闭右开区间 */ void InsertSort(int* head, int* tail){ int *p, *q, tmp; for (p = head; p < tail - 1; ++p){ if (*(p + 1) < *p){ tmp = *(p+1); //设置哨兵值 for (q = p; q >= head && *q > tmp; --q){ *(q + 1) = *q; } //此后q在head的前一位后者在第一个小于哨兵值的位置 *(q + 1) = tmp; } } }