插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得
L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤
L[i],则L[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个
位置j(1≤j≤i-1),使得L[j] ≤L[j+1]时为止。图1演示了对4个元素进行插入排序的过程,共需要(a),(b),(c)三次插入。
图1 对4个元素进行插入排序
在下面的插入排序算法中,为了写程序方便我们可以引入一个哨兵元素L[0],它小于L[1..n]中任一记录。所以,我们设元素的类型
ElementType中有一个常量-∞,它比可能出现的任何记录都小。如果常量-∞不好事先确定,就必须在决定L[i]是否向前移动之前检查当前位置是
否为1,若当前位置已经为1时就应结束第i遍的处理。另一个办法是在第i遍处理开始时,就将L[i]放入L[0]中,这样也可以保证在适当的时候结束第i
遍处理。下面的算法中将对当前位置进行判断。
插入排序算法如下:
procedure Selection_Sort(var L:List);
var
i,j:position;
v:ElementType;
begin
1 for i:=First(L)+1 to Last(L) do
begin
2 v:=L[i];
3 j:=i;
4 while (j<>First(L))and(L[j-1]< v) do //循环找到插入点
begin
5 L[j]:=L[j-1]; //移动元素
6 j:=j-1;
end;
7 L[j]:=v; //插入元素
end;
end;
下面考虑算法Insertion_Sort的复杂性。对于确定的i,内while循环的次数为O(i),所以整个循环体内执行了∑O(i)=O(∑i),其中i从2到n。即比较次数为O(n2
)。如果输入序列是从大到小排列的,那么内while循环次数为i-1次,所以整个循环体执行了∑(i-1)=n(n-1)/2次。由此可知,最坏情况下,Insertion_Sort要比较Ω(n2
)次。
如果元素类型是一个很大的纪录,则算法第5行要消耗大量的时间,因此有必要分析移动元素的次数。经过分析可知,平均情况下第5行要执行n(n-1)/4
次,分析方法与冒泡排序的分析相同。如果移动元素要消耗大量的时间,则可以用链表来实现线性表,这样Insertion_Sort可以改写如下(当然前一
个算法同样也适用于链表,只不过没下面这个好,但是下面算法这个比较复杂):
注意:在下面的算法中链表L增加了一个哨兵单元,其中的元素为-∞,即线性表L的第一个元素是L^.next^
procedure Selection_Sort_II(var L:PList);
var
i,j,tmp:Position;
begin
1 if L^.next=nil then exit; //如果链表L为空则直接退出
2 i:=L^.next; //i指向L的第一个元素,注意,L有一个哨兵元素,因此L^.next^才是L的第一个元素
3 while i^.next<>nil do
begin
4 tmp:=i^.next; //tmp指向L[i]的下一个位置
5 j:=L;
6 while (j<>i)and(tmp^.data>=j^.next^.data) do //从前向后找到tmp的位置,tmp应该插在j后面
7 j:=j^.next;
8 if j<>i then //j=i说明不需要改变tmp的位置
begin
9 i^.next:=tmp^.next; //将tmp从i后面摘除
10 tmp^.next:=j^.next; //在j后面插入tmp
11 j^.next:=tmp;
end
12 else i:=i^.next; //否则i指向下一个元素
end;
end;
上述改进算法主要是利用链表删除和插入元素方便的特性,对于数组则不适用。
插入排序法是一个原地置换排序法,也是一个稳定排序法。插入法虽然在最坏情况下复杂性为θ(n2
),但是对于小规模输入来说,插入排序法是一个快速的原地置换排序法。许多复杂的排序法,在规模较小的情况下,都使用插入排序法来进行排序,比如快速排序和桶排序。
分享到:
相关推荐
一、插入排序(Insertion Sort) 插入排序是一种简单的排序算法。其基本思想是每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。 插入...
图解插入排序——直接插入排序算法(straight insertion sort)
一、插入排序(Insertion Sort) 插入排序是一种简单的排序算法,它的基本思想是每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。 插入...
3. **插入排序(Insertion Sort)** 插入排序将每个元素插入到已排序部分的正确位置。对于小规模或基本有序的数据,插入排序表现良好,但其平均和最坏情况下的时间复杂度都是O(n^2)。 4. **快速排序(Quick Sort)...
在本文中,我们将深入探讨两种基础且重要的排序算法——插入排序和选择排序。这两种排序算法在数据结构和算法的学习中占据着核心地位,因为它们帮助初学者理解排序的基本原理。 首先,我们来看**插入排序...
本文将详细讲解六种经典的排序算法——合并排序、插入排序、希尔排序、快速排序、冒泡排序以及桶排序,并结合提供的文件名(sort.c、set.c、main.c、set.h、sort.h)推测出每个文件可能包含的代码实现。 1. **合并...
总结起来,冒泡排序、插入排序和选择排序都是基于比较的排序算法,它们在不同的场景下各有优劣。冒泡排序适用于小规模数据或接近有序的数据,插入排序在部分有序的数据上表现优秀,而选择排序则在内存限制的环境中...
本文将介绍两种经典的排序算法——直接插入排序和希尔排序,并分别提供C语言和C#语言的实现代码。 1. 直接插入排序 直接插入排序是一种简单的排序算法,其主要思想是通过逐步比较和移动元素来构建一个有序序列。它...
本文将深入探讨两种常见的排序算法——插入排序(Insertion Sort)和快速排序(QuickSort)的Python实现。 首先,我们来看插入排序。插入排序是一种简单直观的排序算法,它的工作原理类似于我们日常生活中的整理...
本文将深入探讨标题和描述中提及的五种经典排序算法——插入排序、归并排序、选择排序、冒泡排序和希尔排序,以及它们在Java中的实现。 1. 插入排序(Insertion Sort) 插入排序是一种简单直观的排序算法,它的工作...
4. **插入排序(Insertion Sort)** 插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间...
通过本实验,我们旨在实现六种常见的排序算法——合并排序、插入排序、希尔排序、快速排序、冒泡排序以及桶排序,并对它们的性能进行比较分析。 #### 实验原理简介 1. **合并排序**(Merge Sort) - **定义**:一...
以下是根据标题和描述中提到的四种排序算法——冒泡排序、快速排序、插入排序和选择排序的详细说明。 **冒泡排序(BuddleSort)**: 冒泡排序是一种简单的交换排序,它通过重复遍历待排序的列表,比较相邻元素并...
根据给定文件的信息,本文将详细介绍C语言中的四种基本排序算法——插入排序、起泡排序、快速排序和选择排序,并对这些算法进行深入解析。 ### 1. 插入排序 (Insertion Sort) 插入排序是一种简单直观的排序方法。...
本文将深入探讨两种经典的排序算法——选择排序和插入排序,并通过Java语言进行具体描述,旨在帮助读者理解这两种算法的工作原理、时间复杂度以及实际应用。 #### 选择排序:效率与简洁性的权衡 选择排序是一种简单...
根据给定文件的信息,本文将对六种不同的排序算法——冒泡排序、直接插入排序、简单选择排序、快速排序、希尔排序以及堆排序——进行详细分析,并比较它们之间的性能差异。 ### 冒泡排序(Bubble Sort) 冒泡排序...
2. 插入排序(Insertion Sort):插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。它在最好情况下(即输入数组已经部分排序)有很好的性能。 3. 选择排序...
首先,让我们从最经典的排序算法——冒泡排序(Bubble Sort)开始。冒泡排序通过不断地交换相邻的不正确顺序的元素来逐步排序数组。它的主要步骤是遍历数组,比较每对相邻元素,如果顺序错误就交换它们。这个过程会...
2. **直接插入排序**(Insertion Sort): 直接插入排序是将一个元素插入到已排序的部分序列中,以保持排序。每次插入都需要比较并可能移动元素。与冒泡排序类似,它的时间复杂度也为O(n^2),但当输入部分有序时,它...
首先,我们来详细讲解插入排序(Insertion Sort)。插入排序的工作原理类似于我们手动整理扑克牌。我们从第一张牌开始,依次将后续的牌与已排序的部分比较,找到合适的位置插入。在Java实现中,我们可以用一个for...