插入排序

    插入排序是一种很容易想到的算法,它的思路和打扑克牌时排列手牌的方法很相似,比如我们现在单手拿牌,然后从左至右、由小到大进行排序。此时我们需要将牌一张张抽出来,分别插入到前面排好序的手牌中的适当位置。重复这一操作指导插入最后一张牌,整个排序就完成了。

伪代码:

insertionSort(A,N)

    for i从1到N-1

        v = A[i]

        j = i-1

        while j>=0且A[j]>v

            A[j+1] = a[j]

            j--

        A[j+1] = v;


将开头元素视作已排序

执行下属处理,直至未排序部分消失

1、取出未排序部分的开头元素赋值给变量v。

2、在已排序部分,将所有比v大的元素向后移动一个单位

3、将已取出的元素v插入空位

举个例子,我们对数组A={8,3,1,5,2,1}进行插入排序,整体流程如下图所示

831521
381521
138521
135821
123581
112358
      

红色字体的是下一次需要插入的数据,绿色字体的是得到该列数据时移动了的数据,字体为灰色的是本次进入有序位的数据。

第一行为初始数据,第二行开始为移动后的数据

    在步骤1(第二行)中,将A[0] 视为已排序,所以我们取出A[1]的3,将其插入到已排序部分的恰当位置。首先把原先位于A[0]的8移动至A[1],再把3插入到A[0]。这样第二个元素就完成了排序。

    在步骤2中,我们要把A[2]的1插入恰当位置。这里首先将比1大的A[1]和A[0],顺次向后移动一个位置,然后把1插入到A[0]。

    在步骤3中,我们要把A[3]的5插入恰当位置。这里首先将比5大的A[2]向后移动一个位置,然后把5插入A[2]。

之后同理,将已排序部分的其中一段向后移动,再把未排序部分的开头元素插入已排序部分的的恰当位置,插入排序的特点在于,只要0到i号元素全部排入已排序部分,那么无论后面如何插入,0到第i号元素都将永远保持排序完毕的状态。

实现插入排序时需要的主要变量如下:

A[N]长度为N的整形数组
i循环变量,表示未排序部分的开头元素
v临时保存A[i]值得变量
j循环变量,用于在已排序部分寻找v的插入位置

外层循环的i从1开始自增。在每次循环开始时,将A[i]的值临时保存在变量v中。

接下来是内部循环。我们要从已排序部分找出比v大的元素并让他们顺次后移一个位置。j从i-1,开始向前自减,同时将比v大的从A[j]移动到A[j+1],一旦j等于-1或者当前a[j]小于v则循环结束,并将v插入到j+1的位置。

分析:

    在插入排序法中,我们只将比v(取出的元素)大的元素向后平移,不相邻的元素不会直接交换位置,因此整个排序算法十分稳定。

    然后我们考虑一下插入排序的时间复杂度。这里需要估算每个i循环中A[j]元素向后移动的次数。最坏的情况下,每个i循环都需要执行i次移动,总共需要1+2+3+4+5+......+N-1=(N*N-N)/2次移动。即算法复杂度为N的平方,在N足够大的时候系数可以不计入复杂度

    插入排序是一种很有趣的算法,输入数据的顺序能够直接影响时间复杂度。最好的情况就是刚好就是我们所需要的顺序,时间复杂度为N,最坏的情况就是数据有序且刚好我们所需要的顺序相反,时间复杂度为N平方。插入排序的优势就在于能快速处理相对有序的数据。

参考代码:

#include<stdio.h>
void print(int A[],int N){
	int i;
	for(i = 0;i < N;i++){
		if(i > 0){
			printf(" ");
		}
		printf("%d",A[i]);
	}
	printf("\n");
} 
void insertSort(int A[],int N){
	int i,j,v;
	for(i = 1;i < N;i++){
		v = A[i];
		j = i -1;
		while(j >= 0&&A[j] > v){
			A[j+1] = A[j];
			j--;
		}
		A[j+1] = v;
		print(A,N);
	}
	

}
int main(){
	int N,i,j;
	int A[100];
	scanf("%d",&N);
	for(i = 0;i < N;i++){
		scanf("%d",&A[i]);
	}
	print(A,N);
	insertSort(A,N);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值