文章目录
直接插入排序是从一个有序的序列中选择一个合适的位置进行插入,这个合适的位置取决于是要升序排序还是降序排序。
每一次进行排序之后,这段数据都是有序的。
提示:以下是本篇文章正文内容,下面案例可供参考
直接插入排序是从一段数据中将一个数据在合适的位置插入。
案例:
一张图弄懂直接插入排序


代码如下:
void InsertSort(int * a,int n )
{
for(int i =0;i<n-1;i++)
{
int end = i;
//保存待插入元素
int tmp = a[end+1];
while(end>=0)
{
if(a[end]>tmp)
{
//把end往后挪
a[end+1] = a[end];
//end再往前走
end--;
}
else
{
break;
}
}
//由于不管是在中间的任意地方插入还是在end的末尾插入(即tmp是最大的情况),
//都是在end后面的位置插入,所以来到这里进行合并
a[end+1] = tmp;
}
}
直接插入排序的时间复杂度为:O(N^2),因为最坏的情况是逆序的情况:

每一次插入需要挪动的次数为:1+2+3+4+…+n-2+n-1 = n*n/2
所以最坏情况下的时间复杂度为O(n^2)
希尔排序可以被认为是优化后的直接插入排序。
具体优化过程如下:
给定一个gap,这个gap是把待插入的数据分成gap组,每组之间的间隔为gap长度
给定一个gap,这个gap是把待插入的数据分成gap组,每组之间的间隔为gap长度
给定一个gap,这个gap是把待插入的数据分成gap组,每组之间的间隔为gap长度
重要的事情说三遍。
比如:

令gap = 3,即待插入的数据的间隔为3,不同于直接插入排序,直接插入排序是第一个和第二个数据的间隔永远为1,而对于希尔排序,当gap = 3时,第一个数据和第二个数据的间隔为3。
当我们把该组的元素两两比较时,大的元素就会更快地往后走。

第二轮是将待插入元素8和9比较,因为9后面的第一个元素不再是7,而是9+gap的位置处的数据,即8
再将9和8进行比较,将8插入到9位置处。
当然,这是每组组内的比较,
放眼整个希尔排序来说,是多组同时进行的。
可以发现,
当gap越大,大的元素越快挪到后面
当gap越小,小的元素越慢挪到后面
当gap == 1时,就相当于上面提到的直接插入排序。
回到上面的案例,gap = 3,所以需要将数据分成3组,每组的间隔为3个长度。

如上图:此时每个元素都可以被覆盖到。

相当于同时把gap组中大的元素更快挪到后面
我们把上面的过程成为:预排序
也就是说,完成上面的操作之后,整个数据并不是有序的,而是 接近有序
比如上面的案例,完成预排序后,整组数据为:

此时是接近有序,所以此时令gap = 1,即最后接近有序的时候进行直接插入排序即可。
注意:gap的取值是不确定的:
gap取值越大,大的数据越快挪到后面,但越不接近有序
gap取值越小,大的数据越慢挪到后面,但越接近有序
总之gap是一定不能固定,并且gap的取值最后必须为1。
gap的取值应该是从大逐渐到小过渡的。
gap的取值一般是:
初始化gap = n,
进入轮回时:
gap = gap/3+1 或者 gap = gap/2,每次轮完一轮后,gap都会减小。
当gap的取值是gap = gap/2时,时间复杂度为:O(N*logN),logN是以2为底N的对数
最坏情况同样为逆序:

最后一轮gap = 1,此时为直接插入排序,则N/2/2/2/…/2 = 1,
每次轮回一次gap,gap都会/2,最后一次gap = 1,则需要比较的次数是logN(以2为底N的对数)
总的时间复杂度为遍历整组元素的次数:O(N)*每次遍历进行插入的次数O(logN)
—> O(N * logN)
同理:当gap的变化是gap = gap/3-1时, 最坏情况下(逆序)每次轮回需要插入的次数是
(((N/3+1) /3+1)/3+1)… = 1
对于时间复杂度:可忽略掉+1项,所以每次轮回插入次数log3 (N) ,以3为底N的对数
总时间复杂度为O(N*log3 (N))
经过前人计算,希尔排序平均时间复杂度为:
O(N^1.3)

实现代码:
void ShellSort(int* a, int n)
{
//当gap越大,大的值越快到达最后的位置,但越不接近有序
//当gap越小,大的值越慢到达最后的位置,但越接近有序
//当gap值越接近1,排序越接近顺序
//刚gap == 1时,就是直接插入排序
int gap = n;
while (gap > 1)
{
//两种方式均可,gap可以任取任何值,但是都必须保证gap最后一定为1
//gap = gap / 2;
gap = gap / 3 + 1;
//在这里就是把间隔多组的数据同时排列
for (int i = 0; i < n - gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
//小于的情况,需要挪动数据
if (a[end] > tmp)
{
a[end + gap] = a[end];
end -= gap;
}
//大于或者等于的情况,直接插入end后面
else
{
break;
}
}
//由于最终都需要插入end后面,所以在循环之外插入
a[end + gap] = tmp;
}
}
}
总结:希尔排序是在直接插入排序的基础上引入一个gap,这个gap把数据分成了gap组,并且每组元素之间的间隔也为gap。
gap每次都会逐渐减小,并且最后gap一定为1,当gap为1时,代表完成了预排序,
最后一步进行直接插入排序。
void TestOP()
{
srand(time(0));
const int N = 1000000;
int* a1 = (int*)malloc(sizeof(int) * N);
int* a2 = (int*)malloc(sizeof(int) * N);
assert(a1 && a2);
for (int i = 0; i < N; ++i)
{
a1[i] = rand();
a2[i] = a1[i];
}
//计算到这个走位置的时间(ms)
int begin1 = clock();
InsertSort(a1, N);
int end1 = clock();
//末位置-初位置就是时间差
int begin2 = clock();
ShellSort(a2, N);
int end2 = clock();
printf("InsertSort:%d\n", end1 - begin1);
printf("ShellSort:%d\n", end2 - begin2);
free(a1);
free(a2);
}
int main()
{
TestOP();
return 0;
}

可以看到,当排序数据为100w个时,直接插入排序和希尔排序差距超过了2000倍。
直接插入排序和希尔排序的效率相比,数据越多,希尔排序较于直接插入排序的优化越大。
我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night
我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195
我正在尝试按Rails相关模型中的字段进行排序。我研究的所有解决方案都没有解决如果相关模型被另一个参数过滤?元素模型classItem相关模型:classPriority我正在使用where子句检索项目:@items=Item.where('company_id=?andapproved=?',@company.id,true).all我需要按相关表格中的“位置”列进行排序。问题在于,在优先级模型中,一个项目可能会被多家公司列出。因此,这些职位取决于他们拥有的company_id。当我显示项目时,它是针对一个公司的,按公司内的职位排序。完成此任务的正确方法是什么?感谢您的帮助。PS-我
我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排
我想知道是否可以通过自动创建数组来插入数组,如果数组不存在的话,就像在PHP中一样:$toto[]='titi';如果尚未定义$toto,它将创建数组并将“titi”压入。如果已经存在,它只会推送。在Ruby中我必须这样做:toto||=[]toto.push('titi')可以一行完成吗?因为如果我有一个循环,它会测试“||=”,除了第一次:Person.all.eachdo|person|toto||=[]#with1billionofperson,thislineisuseless999999999times...toto.push(person.name)你有更好的解决方案吗?
例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果
在我的用户模型中,我有一堆属性,例如is_foos_admin和is_bars_admin,它们决定允许用户编辑哪些类型的记录。我想干掉我的编辑链接,目前看起来像这样:'edit'ifcurrent_user.is_foos_admin?%>...'edit'ifcurrent_user.is_bars_admin?%>我想做一个帮助程序,让我传入一个foo或bar并返回一个链接来编辑它,就像这样:助手可能看起来像这样(这不起作用):defedit_link_for(thing)ifcurrent_user.is_things_admin?link_to'Edit',edit_poly
我有一个对象如下:[{:id=>2,:fname=>"Ron",:lname=>"XXXXX",:photo=>"XXX"},{:id=>3,:fname=>"Dain",:lname=>"XXXX",:photo=>"XXXXXXX"},{:id=>1,:fname=>"Bob",:lname=>"XXXXXX",:photo=>"XXXX"}]我想按fname排序,不区分大小写,所以它会导致编号:1,3,2我该如何排序?我正在尝试:@people.sort!{|x,y|y[:fname]x[:fname]}但这没有任何效果。 最佳答案
有人可以告诉我如何根据自定义字符串对嵌套数组进行排序吗?比如有没有办法排序:[['Red','Blue'],['Green','Orange'],['Purple','Yellow']]“橙色”、“黄色”,然后是“蓝色”?最终结果如下所示:[['Green','Orange'],['Purple','Yellow'],['Red','Blue']]它不是按字母顺序排序的。我很想知道我是否可以定义要排序的值以实现上述目标。 最佳答案 sort_by对于这种排序总是非常方便:a=[['Red','Blue'],['Green','Ora
我有以下现有的Dog对象数组,它们按age属性排序:classDogattr_accessor:agedefinitialize(age)@age=ageendenddogs=[Dog.new(1),Dog.new(4),Dog.new(10)]我现在想插入一条新的狗记录,并将它放在数组中的正确位置。假设我想插入这个对象:another_dog=Dog.new(8)我想把它插入到数组中,让它成为数组中的第三项。这是一个人为的示例,旨在演示我特别想如何将一个项目插入到现有的有序数组中。我意识到我可以创建一个全新的数组并重新对所有对象进行排序,但这不是我的目标。谢谢!