我试图了解插入排序和选择排序之间的区别。
它们似乎都具有两个组成部分:未排序列表和已排序列表。他们似乎都从未排序列表中选取一个元素,并将其放入适当位置的已排序列表中。我见过一些网站/书籍说选择排序是通过一次交换一个来实现的,而插入排序只是找到合适的位置并插入它。但是,我看到其他文章说了一些话,说插入排序也会互换。因此,我感到困惑。有规范的资料吗?
我试图了解插入排序和选择排序之间的区别。
它们似乎都具有两个组成部分:未排序列表和已排序列表。他们似乎都从未排序列表中选取一个元素,并将其放入适当位置的已排序列表中。我见过一些网站/书籍说选择排序是通过一次交换一个来实现的,而插入排序只是找到合适的位置并插入它。但是,我看到其他文章说了一些话,说插入排序也会互换。因此,我感到困惑。有规范的资料吗?
Answers:
给定一个列表,获取当前元素并将其与当前元素右侧的最小元素交换。
给定一个列表,将当前元素插入到列表的适当位置,并在每次插入时调整列表。这类似于在纸牌游戏中安排纸牌。
选择排序的时间复杂度总是不变的n(n - 1)/2
,而插入排序的时间复杂度最好,因为它的最坏情况是n(n - 1)/2
。通常,然后需要进行更少或相等的比较n(n - 1)/2
。
来源:http://cheetahonfire.blogspot.com/2009/05/selection-sort-vs-insertion-sort.html
插入排序和选择排序都具有一个外循环(在每个索引上)和一个内循环(在索引的子集上)。内循环的每次遍历都会将排序区域扩展一个元素,但以未排序区域为代价,直到用尽未排序元素为止。
区别在于内部循环的作用:
在选择排序中,内部循环位于未排序的元素上。每遍都选择一个元素,然后将其移动到其最终位置(在已排序区域的当前末端)。
在插入排序中,内部循环的每个遍历都会迭代排序后的元素。已排序的元素将移位,直到循环找到正确的位置以插入下一个未排序的元素。
因此,在选择排序中,以输出顺序找到排序后的元素,并在找到它们后保持原样。相反,在插入排序中,未排序的元素将保持放置状态,直到按输入顺序消耗为止,而已排序区域的元素将继续四处移动。
就交换而言:选择排序每次对内循环进行一次交换。插入排序通常像temp
在内部循环之前一样保存要插入的元素,为内部循环留出空间将已排序的元素上移一个,然后再复制temp
到插入点。
选择排序
假设有一个以特定/随机方式写的数字数组,可以说我们要按升序排列。因此,一次取一个数字,然后用最小的数字代替。在列表中可用。通过执行此步骤,我们最终将获得期望的结果。
插入排序
请记住类似的假设,但是唯一的区别是,这次我们一次选择一个数字,然后将其插入预先排序的部分中,这减少了比较,因此效率更高。
造成混淆的原因可能是因为您正在将对链表进行排序的描述与对数组进行排序的描述进行比较。但是我不确定,因为您没有引用您的消息来源。
理解排序算法的最简单方法通常是获得该算法的详细说明(不要含糊不清,例如“这种排序使用交换。在某处。我不是说在哪里”),得到一些扑克牌(5-10应该足够了) (用于简单的排序算法),然后手动运行该算法。
选择排序:浏览未排序的数据以寻找剩余最小的元素,然后将其交换到紧接排序后的数据之后的位置。重复直到完成。如果对列表进行排序,则无需将最小的元素交换到位置,而是可以将列表节点从其旧位置移除,然后将其插入新位置。
插入排序:在排序后的数据之后立即获取元素,浏览排序后的数据以找到放置位置,然后将其放置在该位置。重复直到完成。
插入排序可以在其“扫描”阶段使用交换,但不是必须的,这不是最有效的方法,除非您对以下数据类型的数组进行排序:(a)无法移动,只能复制或交换;(b)复制比交换更昂贵。如果插入排序确实使用了swap,那么它的工作方式是同时搜索位置并将新元素放在此处,方法是将新元素与紧接其前的元素重复交换一次,只要它之前的元素大于它。到达不大的元素后,您将找到正确的位置,然后继续下一个新元素。
两种算法的逻辑都非常相似。它们都在数组的开头具有部分排序的子数组。唯一的区别是他们如何搜索要放入已排序数组中的下一个元素。
插入排序:将下一个元素插入正确的位置;
选择排序:选择最小的元素并与当前项目交换;
而且,与Selection Sort相反,Insertions Sort是稳定的。
我在python中都实现了,值得注意的是它们有多么相似:
def insertion(data):
data_size = len(data)
current = 1
while current < data_size:
for i in range(current):
if data[current] < data[i]:
temp = data[i]
data[i] = data[current]
data[current] = temp
current += 1
return data
进行很小的更改就可以做出选择排序算法。
def selection(data):
data_size = len(data)
current = 0
while current < data_size:
for i in range(current, data_size):
if data[i] < data[current]:
temp = data[i]
data[i] = data[current]
data[current] = temp
current += 1
return data
我将再尝试一次:考虑在几乎排序的数组的幸运情况下会发生什么。
在排序时,可以将数组视为具有两个部分:左侧-已排序,右侧-未排序。
插入排序-选择第一个未排序的元素,然后尝试在已排序的部分中为其找到位置。由于您是从右到左搜索的,因此很可能会发生以下情况:与之比较的第一个排序元素(最大的,最右边的部分在左侧)小于选择的元素,因此您可以立即继续下一个未排序的元素。
选择排序-选择第一个未排序的元素,然后尝试查找整个未排序部分的最小元素,并在需要时交换这两个元素。问题是,由于正确的部分没有排序,因此您每次都必须考虑每个元素,因为您可能无法确定是否存在比所选择的元素还要小的元素。
插入排序的内部循环遍历已排序的元素(与选择排序相反)。这样,当找到正确的位置时,它可以中止内部循环。意思就是:
选择排序必须始终遍历所有内部循环元素。这就是为什么插入排序优先于选择排序的原因。但是,另一方面,选择排序执行的元素交换要少得多,这在某些情况下可能更重要。
基本上,插入排序是通过一次比较两个元素来完成的,而选择排序则从整个数组中选择最小的元素并对其进行排序。
从概念上讲,插入排序通过比较两个元素直到对整个数组进行排序来继续对子列表进行排序,而选择排序选择了最小元素并将其交换到第一个位置,第二个最小元素交换到了第二个位置,依此类推。
插入排序可以显示为:
for(i=1;i<n;i++)
for(j=i;j>0;j--)
if(arr[j]<arr[j-1])
temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
选择排序可以显示为:
for(i=0;i<n;i++)
min=i;
for(j=i+1;j<n;j++)
if(arr[j]<arr[min])
min=j;
temp=arr[i];
arr[i]=arr[min];
arr[min]=temp;
一个简单的解释如下:
给定:未排序的数组或数字列表。
问题陈述:以升序对数字列表/数组进行排序,以了解选择排序和插入排序之间的区别。
插入排序:您会从上到下查看列表,以方便理解。我们将第一个元素视为初始最小值。现在,我们的想法是,我们线性遍历该列表/数组的每个索引,以找出在任何索引处是否还有其他元素的值小于初始最小值。如果找到这样的值,我们只交换它们索引处的值,即假设15是索引1的最小初始值,并且在线性遍历索引期间,我们遇到了一个数值较小的数字,例如索引9处为7。现在,将索引9处的值7替换为值为15的索引1。该遍历将继续与当前索引的值进行比较,其余索引交换为较小的值。这一直持续到列表/数组的倒数第二个索引为止,
选择排序:假设列表/数组的第一个索引元素已排序。现在,从第二个索引处的元素开始,将其与先前的索引进行比较,以查看该值是否较小。遍历可以可视化为两个部分,已排序和未排序。对于列表/数组中的给定索引,将可视化从未排序到已排序的比较检查。假设您的索引1的值为19,索引3的值为10。我们考虑从未排序到已排序(即从右到左)的遍历。因此,假设我们必须对索引3进行排序。从右向左比较时,我们看到它的值小于索引1。一旦确定,我们就将索引3的这个数字10放在具有值19的索引1的位置。索引1的原始值19向右移了一位。
我没有添加任何代码,因为问题似乎在于了解遍历方法的概念。
插入排序不交换东西。即使它使用了temp变量,使用temp var的要点是,当我们发现索引中的值与前一个索引的值相比较小时,我们将较大的值移至较小值的位置会写东西的索引。然后,我们使用temp var替换上一个索引。示例:10、20、30、50、40。迭代1:10、20、30、50、50。[temp = 40]迭代2:10、20、30、40(温度值),50。只需在某个变量的所需位置插入一个值即可。
但是,当我们考虑选择排序时,我们首先找到具有较低值的索引,然后将其与第一个索引中的值交换,并继续重复交换直到所有索引都得到排序。这与两个数字的传统交换完全相同。示例:30,20,10,40,50。迭代1:10,20,30,40,50。此处temp var仅用于交换。
它们两者的共同点是它们都使用分区来区分数组的排序部分和未排序的部分。
所不同的是,通过选择排序,可以确保在将元素添加到已排序分区中时,数组的已排序部分不会改变。
原因是,因为选择搜索未排序集的最小值,然后将其添加到排序集的最后一个元素之后,因此将排序集增加了1。
另一方面,插入仅关心关心的下一个元素,它是数组未排序部分中的第一个元素。它将使用此元素并将其简单地放入已排序集中的适当位置。
对于仅部分排序的数组,插入排序通常通常是更好的候选方法,因为您正在浪费时间来寻找最小值。
结论:
选择排序通过在未排序部分中找到最小元素,将元素逐渐添加到末尾。
插入排序会将未排序部分中找到的第一个元素传播到排序部分中的任何位置。
尽管选择排序和插入排序的时间复杂度相同,但为n(n-1)/ 2。平均性能插入排序更好。在我的i5 CPU上测试了30000个随机整数,选择排序平均花费1.5s,而插入排序平均花费0.6s。
选择-选择一个特定的项目(最低的项目)并将其与第i(迭代次数)个元素交换。(即第一,第二,第三……),因此将排序列表放在一边。
插入-首先与第二个进行比较,然后与第二个进行比较,然后再将第三个与第二个进行比较,然后将第一个与第四个进行比较。