八大排序(一)

本章重点:

<>插入排序

<>选择排序

<>希尔排序

(一)插入排序

基本思想:

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

动画演示为:

八大排序(一)_第1张图片

思路:
在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。
但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。
 

// 插入排序
void InsertSort(int* a, int n)
{
	assert(a);
	for (int i = 0; i < n - 1; i++)//将一个数组中所有元素升序
	{                              //,这里必须是n-1,不然后面数组会越界
		int end=i;
		int x=a[end+1];//x始终指向end下一个位置的值
		while (end >= 0)//每趟插入最多挪动end-1个数据
		{
			if (a[end] > x)//x前一个数大于x,就将数据往后移一格
			{
				a[end + 1] = a[end];//这里数组的值会往后覆盖
				                    //但是没关系,我们已经将a[end+1]的值保存在x当中了
				end--;
			}
			else
			{
				break;//跳出里面的while循环
			}
		}
		a[end + 1] = x;
	}
}

时间复杂度:最坏情况下为O(N*N),此时待排序列为逆序,或者说接近逆序
      最好情况下为O(N),此时待排序列为升序,或者说接近升序。
空间复杂度:O(1)

 

(二)选择排序

基本思想:

每次从待排序的数据元素中选出最小的(最大的)一个元素,存放在序列的起始位置,直到全部待排数据元素排完。

动画演示:

八大排序(一)_第2张图片

 代码:

//选择排序
void swap(int* a, int* b)
{
	int tem = *a;
	*a = *b;
	*b = tem;
}
void SelectSort(int* arr, int n)
{
	//保存参与单趟排序的第一个数和最后一个数的下标
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		//保存最大值的下标
		int maxi = begin;
		//保存最小值的下标
		int mini = begin;
		//找出最大值和最小值的下标
		for (int i = begin; i <= end; ++i)
		{
			if (arr[i] < arr[mini])
			{
				mini = i;
			}
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}
		}
		//最小值放在序列开头
		swap(&arr[mini], &arr[begin]);
		//防止最大的数在begin位置被换走
		if (begin == maxi)
		{
			maxi = mini;
		}
		//最大值放在序列结尾
		swap(&arr[maxi], &arr[end]);
		++begin;
		--end;
	}
}

时间复杂度:最坏情况:O(N^2)
      最好情况:O(N^2)
空间复杂度:O(1)

 (三)希尔排序

基本思路:

  • 在直接插入排序上做优化:
    1. 分组预排序,使数组接近有序
    2. 直接插入排序

为什么这么做?

我们在将插入排序的时候提到:对于有序的数组插入排序的时间复杂度为O(N).

所以这里我们先预排序,让数组接近有序再去直接插入排序这样效率会大大提升!

预排序思路讲解 

  1. 将一个数组按gap分组.
  2. 再将分组的值进行插入排序

假设这里的gap等于3:

八大排序(一)_第3张图片 

这里,9.5.8.5分为一组
1.7.6 分为一组
2.4.3 分为一组

再将数据: 9.5.8.5进行插入排序
1.7.6进行插入排序
2.4.3进行插入排序

排完后变成了这样:

八大排序(一)_第4张图片

单独看红色一组:5.5.8.9.是有序的
单独看绿色一组:1.6.7.也是有序的
单独看蓝色一组:2.3.4.也是有序的
数组整体比刚才有序了,目的达到!

 实现步骤:

1.先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在同一组,并对每一组的元素进行直接插入排序。然后再取一个比第一增量小的整数作为第二增量,重复上述操作…
2.当增量的大小减到1时,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。

动图如下: 

 

思路:
希尔排序,先将待排序列进行预排序,使待排序列接近有序,然后再对该序列进行一次插入排序,此时插入排序的时间复杂度为O(N), 

代码如下:

//希尔排序
void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap>1)
	{
		//每次对gap折半操作
		gap = gap / 2;
		//单趟排序
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tem = arr[end + gap];
			while (end >= 0)
			{
				if (tem < arr[end])
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tem;
		}
	}
}

时间复杂度平均:O(N^1.3)
空间复杂度:O(1)

你可能感兴趣的:(八大排序,排序算法,算法,数据结构)