插入排序+希尔排序

目录

插入排序

1.基本思想

2.单个元素插入有序数组图解

3.插入排序图解

4.代码

5.复杂度与稳定性

希尔排序

1.基本思想

2.图解

3.代码

4.复杂度与稳定性


插入排序

1.基本思想

        把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为 止,得到一个新的有序序列。

2.单个元素插入有序数组图解

要把数字 3 插入到下面的数组中,使其成为一个升序的数组:
int arr[5]={1,2,4,5};
观察数组发现,数组本就升序,那么插入时就很简单了。插入的步骤为:
1.比较5与3的大小,发现5比3大,那么5往后移动,覆盖后一个位置的值:

 2.然后在比较4与3的大小,发现4比3大,那么4往后移动,覆盖后一个位置的值:

 3.在继续比较2与3的大小,发现2比3小,那么此时2后边的位置就是待插入的位置,把3插入后:

 完成了将3插入依然保证数组升序。注意:此时的插入只能从后往前比较,因为数组后有空位置。

完成了在单个升序数组中将元素插入,这一操作给了我们启发,假如现在有一乱序的数组,我们怎么进行插入排序呢?

3.插入排序图解

给定一组数据:

int arr[5]={6,2,1,3,4};

1.首先可以将数组的第一个元素6看作是一个升序数组,那么问题就变成了将数字2进行插入,使前两个元素称为一个升序的数组,插入2后:

 2.此时将上图中2和6看作是一个升序的数组,数字1为待插入的数值,将1插入后:

 3.再将1、2、6这三个数值看作一个升序数组,数字3为待插入数值,插入后:

 4.最后一次将前四个数值看作是一个升序的数组,将数值4进行插入,插入后:

 完成以上步骤就完成了整个的插入排序。

4.代码

void InsertSort(int* arr, int size){
	for (int i = 0; i < size - 1;i++){
		int end = i;//记录每次待插入数值前一个位置的数组下标
		int data = arr[end + 1];//待插入的数值
		while (end >= 0 && arr[end]>data){
			arr[end + 1] = arr[end];
			end--;
		}
		arr[end + 1] = data;
	}
}

在以上代码中,外层循环表示要插入的轮数,比如有5个元素,那么就要进行4轮插入。内层循环的作用是寻找每次插入的位置。注意:end从0开始,此时满足一开始将第一个元素视作单独数组,而且end<size-1;那么arr[end+1]也刚好不会越界,满足要求。

5.复杂度与稳定性

时间复杂度:O(N^2);

空间复杂度:O(1);

稳定性:稳定(注意while循环中arr[end]<data,不能带等号)

希尔排序

1.基本思想

先选定一个整数,把待排序文件中所有记录分成 组,所有距离为此整数的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工 作。当分组到达1时,所有记录在统一组内排好序

2.图解

假如有以下一组数据:

int arr[]={2,6,3,8,4,1,7,9,5};

1.开始给定整数为gap=3,分组后对每一组分别排序:

 2.gap自减1,接下来距离为2是一组,分组后对每一组分别排序:

 3.gap在自减1,最后一次每1个一组,分组后对每一组分别排序:

 以上步骤就是用希尔排序的思想完成的。

3.代码

void ShellSort(int* arr,int size){
	int gap = 3;
	while (gap){
		for (int i = 0; i<size-gap; i++){
			int end = i;
			int data = arr[end + gap];
			while (end>=0&&arr[end]>data){
				arr[end + gap] = arr[end];
				end -= gap;
			}
			arr[end + gap] = data;
		}
		gap--;
	}
}

根据上述代码,可以发现希尔排序内部利用插入排序进行的,只是将数据划分成了组,进行了多次排序,所以说:希尔排序是对直接插入排序的优化。

此时注意end的取值范围,必须保证end+gap不能越界。

4.复杂度与稳定性

时间复杂度:

空间复杂度:O(1)

稳定性:不稳定

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值