插入排序、希尔排序、选择排序

1.插入排序

1.1实现

将数组在逻辑上看做有序序列和无序序列两个部分,每次从无序序列中挑选出来一个元素在有序序列中插入进去;

下面都将以升序为例
在这里插入图片描述

实现代码:

void InsertSort(int *arr, int size)//插入排序
{
    
    
	for (int i = 0; i < size - 1; i++)//升序
	{
    
    
		int end = i;//有序数组的最后一个元素下标
		int key = arr[end + 1];//无序数组的第一个元素
		while (end >= 0 && arr[end]>key)
		{
    
    
			arr[end + 1] = arr[end];//往后挪动一个位置
			end--;
		}
		arr[end + 1] = key;
	}

	//for (int i = 0; i < size - 1; i++)//降序
	//{
    
    
	//	int end = i;
	//	int key = arr[end + 1];
	//	while (end >= 0&&arr[end] < key)
	//	{
    
    
	//		arr[end + 1] = arr[end];
	//		end--;
	//	}
	//	arr[end + 1] = key;
	//}

}

1.2特性

1.元素集合越接近有序,直接插入排序算法的时间效率越高;

2.适用于小规模数据或者基本有序时十分高效;

2.时间复杂度:最好为已经是有序序列,时间复杂度为O(N)。最差为逆序,时间复杂度为O(N^2);

3.空间复杂度:常数个空间,O(1);

4.稳定性:不改变相对位置,具有稳定性;

5.数据敏感度:原先数组的有效程度对排序时间复杂度的影响非常大,因此数据敏感度为敏感;

2.希尔排序

2.1实现

希尔排序是插入排序的优化版本,由上述插入排序我们知道,数组中元素的有序程度越高,时间效率就越高。

因此我们需要想办法提高数组的有序程度,于是乎就有了希尔排序法,起始希尔排序法的本质也是插入排序法,只不过将插入排序的间隔改变了;

希尔排序法是先将数组进行分组(逻辑上)排序,这样在整体上就提高了数组的有序程度。数组的有序程度提高了,插入排序的时间效率也就提高了;

gap越大,前面的数据可以越快到后面,后面小的数可以越快到前面。gap越大,越不接近有序,gap越小越接近有序。如果gap=1其实就相当于直接插入排序,就有序了;

下面我用图形来解释一下这个过程
在这里插入图片描述
实现代码:

void ShellSort(int *arr, int size)
{
    
    
	int gap = size;
	while (gap > 1)
	{
    
    
		gap = gap / 2;//每次的步距为gap
		for (int i = 0; i < size - gap; i++)
		{
    
    
			int end = i;//有序的最后一个元素的下标
			int key = arr[end + gap];
			while (end >= 0 && arr[end]>key)
			{
    
    
				arr[end + gap] = arr[end];//往后挪动一个位置
				end -= gap;
			}
			arr[end + gap] = key;
		}
	}
}

2.2特性

1.希尔排序法是对直接插入排序的优化;

2.gap>1时都是进行预排序,即为了提高数组的有序程度;

3.时间复杂度:时间复杂度需要进行推导,这里直接给出结论,平均时间复杂度为O(N^1.3- N^2);

4.空间复杂度:O(1);

5.稳定性:不具有稳定性,相同的元素在分组时可能会被岔开,然后改变相对位置;

6.数据敏感度:敏感,因为本质也是插入排序;

7.当数组有序时,性能比插入排序的效率会低一点,但是总体性能要比插入排序高出很多;

3.选择排序

3.1实现

通过遍历数组,每次选取其中的最大值和最小值放在数组头和尾;

在这里插入图片描述
实现代码:

void Swap(int *arr, int sub1, int sub2)
{
    
    
	int temp = arr[sub1];
	arr[sub1] = arr[sub2];
	arr[sub2] = temp;
}

void SelectSort(int *arr, int size)
{
    
    
	int begin = 0;
	int end = size - 1;
	
	while (begin < end)
	{
    
    
		int min = begin;//较小值坐标
		int max = end;//较大值坐标
		for (int i = begin; i <= end; i++)
		{
    
    
			if (arr[i] < arr[min])//取得新的较小值坐标
				min = i;
			if (arr[i] > arr[max])//取得新的较大值坐标
				max = i;
		}
		Swap(arr, begin, min);//较小值放入有序部分
		
		if (max == begin)//有可能begin对应的值已经和min对应的值发生了交换
			max = min;
		Swap(arr, end, max);//较大值放入有序部分
		begin++;
		end--;
	}
}

3.2特性

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

2.空间复杂度:O(1);

3.数据稳定性:不稳定,从前往后遍历,如果是遇到了最大值,那么相对顺序就会改变

4.数据敏感度:不敏感,无论数组是否有序都需要进行循环;

猜你喜欢

转载自blog.csdn.net/ych9527/article/details/112338137