赞
踩
直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想
我们首先写出插入排序只排一趟的代码,如下图所示,假设数组[0,end]已经是有序数组,那么我们的待排序元素的下标就是end+1,该下标(end+1)元素存入tmp,然后与a[end]进行比较,只要tmp<a[end],就让下标为end的元素向后挪同时end左移,向后挪动是为了腾出空间让tmp插入,直到tmp不满足条件我们就停止循环,将tmp插入到合适的位置end+1中。
这样一趟插入排序的代码就可以写出来了
int end=i; //有序数组最后一个元素的下标 int tmp = a[end + 1]; //待插入元素存入临时变量tmp while (end >= 0) { if (tmp < a[end]) //如果待插入元素比end下标的元素小 { a[end + 1] = a[end]; //1.end下标元素向后挪方便tmp的插入 --end; //2.end左移进行下一轮的比较 } else //如果待插入元素大于或等于end下标的元素退出循环 { break; } } a[end + 1] = tmp; //将tmp插入到数组当中
完整代码只需要让end动起来就可以实现插入排序了,我们默认end=0,即第一个元素是有序,那么只要让end向后移动,让每一个元素和前面排好顺序的元素比较就可以了,end的起始条件是从0开始,结束是end=n-2,因为当end=n-2时,待排序的元素下标就是n-1,即数组的最后一个元素下标,end的区间就是[0,n-2],通常我们喜欢将这个区间写为左闭右开,即[0,n-1)
// 插入排序 void InsertSort(int* a, int n) { //默认第一个数已经是有序 for (int i = 0; i < n-1; ++i) { int end=i; //有序数组最后一个元素的下标 int tmp = a[end + 1]; //待插入元素存入临时变量tmp while (end >= 0) { if (tmp < a[end]) //如果待插入元素比end下标的元素小 { a[end + 1] = a[end]; //1.end下标元素向后挪方便tmp的插入 --end; //2.end左移进行下一轮的比较 } else //如果待插入元素大于或等于end下标的元素退出循环 { break; } } a[end + 1] = tmp; //将tmp插入到数组当中 } }
测试结果
//打印数组 void PrintArr(int* a, int n) { for (int i = 0; i < n; ++i) { printf("%d ", a[i]); } printf("\n"); } void TestInsertSort() { int a[] = { 2,4,7,2,6,4,5,7,8,32,33,11 }; int n = sizeof(a) / sizeof(a[0]); PrintArr(a, n); InsertSort(a, n); PrintArr(a, n); } int main() { TestInsertSort(); system("pause"); return 0; }
直接插入排序的特性总结:
希尔排序法又称缩小增量法。希尔排序法的基本思想是:
先选定一个整数gap(据计算gap=gap/3+1时最优),把待排序数组分成gap个组,所有距离为gap的元素分在同一组内,并对每一组内的元素进行排序。然后,重新选定一个整数 gap,重复上述分组和排序的工作。当gap=1时,则执行直接插入排序,保证所有元素的有序。
同样的,我们假设数组长度n=10,gap=gap/3+1,那么我们先来写出一组排序的代码
首先我们定义变量end=0从数组第一个元素9开始,下一个待插入的元素tmp就是end+gap下标的元素也就是7,我们可以发现规律,当end走到元素4时,4的下标为5,那么我们就可以确定end的区间下标为[0,5],通常我们喜欢将右边的区间变为开区间,你可以发现刚好是[0,n-gap),如果你不相信,可以继续看2,3步骤分析,这样我们就可以写出一组的排序代码了
gap = gap/3+1; for (int i = 0; i < n - gap; ++i) //i从0开始到n-gap结束 { int end = i; int tmp = a[end + gap]; //每次增加gap的步长作为插入元素 while (end >= 0) { if (tmp < a[end]) //如果待插入元素比end下标的元素小 { a[end + gap] = a[end]; //1.end下标元素向后挪方便tmp的插入,这里end挪动的步长是gap而不是1了 end -= gap; //2.end左移进行下一轮的比较,同理左移gap步长 } else //如果待插入元素大于或等于end下标的元素退出循环 { break; } a[end + gap] = tmp; //将tmp插入到数组当中 } }
理解了希尔排序的步骤后,我们只需要写出gap从4到2再到1的循环代码就可以了,这一步很简单,首先定义gap=n, 每次循环gap=gap/3+1, 最后+1是为了保证gap最后能等于1,也就是保证数组有序。
// 希尔排序 gap = gap/3+1 void ShellSort1(int* a, int n) { //1.gap>1时为预排序,让数列更接近有序 //2.gap=1为直接插入排序,保证有序 int gap = n; while (gap > 1) { gap = gap / 3 + 1; //通常的 for (int i = 0; i < n - gap; ++i) //i从0开始到n-gap结束 { int end = i; int tmp = a[end + gap]; //每次增加gap的步长作为插入元素 while (end >= 0) { if (tmp < a[end]) //如果待插入元素比end下标的元素小 { a[end + gap] = a[end]; //1.end下标元素向后挪方便tmp的插入,这里end挪动的不长是gap而不是1了 end -= gap; //2.end左移进行下一轮的比较,同理左移gap步长 } else //如果待插入元素大于或等于end下标的元素退出循环 { break; } a[end + gap] = tmp; //将tmp插入到数组当中 } } } }
测试结果
void TestShellSort()
{
int a[] = { 2,4,7,2,6,4,5,7,8,32,33,11 };
int n = sizeof(a) / sizeof(a[0]);
PrintArr(a, n);
ShellSort1(a, n);
PrintArr(a, n);
}
int main()
{
//TestInsertSort();
TestShellSort();
system("pause");
return 0;
}
// 希尔排序 void ShellSort2(int* a, int n) { //1.gap>1时为预排序,让数列更接近有序 //2.gap=1为直接插入排序,保证有序 int gap = n; while (gap > 1) { gap = gap / 2; //通常的 for (int i = 0; i < n - gap; ++i) //i从0开始到n-gap结束 { int end = i; int tmp = a[end + gap]; //每次增加gap的步长作为插入元素 while (end >= 0) { if (tmp < a[end]) //如果待插入元素比end下标的元素小 { a[end + gap] = a[end]; //1.end下标元素向后挪方便tmp的插入,这里end挪动的不长是gap而不是1了 end -= gap; //2.end左移进行下一轮的比较,同理左移gap步长 } else //如果待插入元素大于或等于end下标的元素退出循环 { break; } a[end + gap] = tmp; //将tmp插入到数组当中 } } } }
希尔排序的特性总结:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。