排序--插入排序&&希尔排序

本文详细介绍了两种插入排序算法:直接插入排序和二分插入排序,并对比了它们的时间复杂度。此外,还介绍了希尔排序(缩小增量排序)的概念及其实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.插入排序

1.直接插入排序

简单说明:是一种稳定的排序算法(稳定就是说两个数的大小一样的话不会交换位置),时间复杂度为O(N^2)

插入排序的时间复杂度分析。在最坏情况下,数组完全逆序,插入第2个元素时要考察前1个元素,插入第3个元素时,要考虑前2个元素,……,插入第N个元素,要考虑前 N - 1 个元素。因此,最坏情况下的比较次数是 1 + 2 + 3 + ... + (N - 1),等差数列求和,结果为 N^2 / 2,所以最坏情况下的复杂度为 O(N^2)

最好情况下,数组已经是有序的,每插入一个元素,只需要考查前一个元素,因此最好情况下,插入排序的时间复杂度为O(N)

算法很简单:就是取两个变量end和key,end指向排序好的序列的最后一个元素的下标,排序好的序列最后一个元素的后面那个元素的值即没有排序的那个值,然后比较两个值,如果要排序升序的话,则key小于array[end]的话,则将array[end]往后移一位,即移动到key的位置,然后end--向前指,用key继续和其比较,如果key还是小于array[end]的话继续将这个array[end]这个元素向后移动一位,如果key不小于array[end]的值的话,则将其插入到之前刚移动的元素的位置,即array[end+1]=key.


代码如下:

void InsertSort(int *array,size_t size)//插入排序,不需要借助新空间
{
	for (size_t i = 1; i < size; ++i) 
	{
		int key = array[i];
		int end = i - 1;
		//找当前元素需要插入的位置
		while (end>=0&&key < array[end])//end>0避免end越界
		{
			array[end + 1] = array[end];//往后搬移
			--end;
		}
		array[end + 1] = key;
	}
}
2.二分插入排序
因为从直接插入排序的过程中我们可以看出来,key之前的序列都是已经排序好的序列,所以对于排序好的序列我们都可以使用二分查找法,即使用二分查找法,通过比较在前面 已经排好的序列中找出要把key所插入的位置就可以了。这样的话就不需要我们一个一个去end--比较了,所以效率比较高一点


代码如下:

void InsertSort_OP(int *array, size_t size)
{
	for (size_t i = 1; i < size; i++)
	{
		int left = 0;
		int right = i - 1;
		int mid = 0;
		int key = array[i];
		while (left <= right)
		{
			mid = (right - left) / 2 + left;
			if (key < array[mid])
			{
				right = mid - 1;
			}
			else
			{
				left = mid + 1; 
			}
		}
		//上述算法找到要出入的位置以后下面开始搬移元素
		int end = i - 1;
		while (end>=left)//这里end>left或者right都可以,=left意思需要将left当前位置的元素搬走就可以了
		{
			array[end + 1] = array[end];
			--end;
		}
		//插入元素
		array[left] = key;
	}
}

二分查找的时间复杂度也是O(N^2),因为他只是 减少了查找的插入点的 次数,移动的次数和遍历的次数是不变的。

二.希尔排序(缩小增量排序)
希尔排序是 插入排序 的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法

时间复





上述是整个希尔排序的流程图,下面给出代码,参考代码理解

void ShellSort(int *array, size_t size)
{
	int gap = size;
	while (gap>1 )
	{
		gap = gap / 3 + 1;
		for (size_t i = gap; i < size; i++)
	  {
		int key = array[i];
		int end = i- gap;
		//找当前元素需要插入的位置
		while (end >= 0 && key < array[end])//end>0避免end越界
		{
			array[end + gap] = array[end];//往后搬移
			end -= gap;
		 }
		array[end + gap] = key;
	  }
		/*gap--;*/
	}
}

下面 在给出完整的代码 和测试程序

#include<iostream>
using namespace std;

//直接插入
void InsertSort(int *array,size_t size)//插入排序,不需要借助新空间
{
	for (size_t i = 1; i < size; ++i) 
	{
		int key = array[i];
		int end = i - 1;
		//找当前元素需要插入的位置
		while (end>=0&&key < array[end])//end>0避免end越界
		{
			array[end + 1] = array[end];//往后搬移
			--end;
		}
		array[end + 1] = key;
	}
}
//时间复杂度
//空间复杂度
//稳定性,给成等号的话就不稳定,不加等号得到话是稳定的
//上述方法效率太低,既然前面已经排好序了就可以使用二分查找

//二分查找的插入排序,效率高
void InsertSort_OP(int *array, size_t size)
{
	for (size_t i = 1; i < size; i++)
	{
		int left = 0;
		int right = i - 1;
		int mid = 0;
		int key = array[i];
		while (left <= right)
		{
			mid = (right - left) / 2 + left;
			if (key < array[mid])
			{
				right = mid - 1;
			}
			else
			{
				left = mid + 1; 
			}
		}
		//上述算法找到要出入的位置以后下面开始搬移元素
		int end = i - 1;
		while (end>=left)//这里end>left或者right都可以,=left意思需要将left当前位置的元素搬走就可以了
		{
			array[end + 1] = array[end];
			--end;
		}
		//插入元素
		array[left] = key;
	}
}

//数据量大杂乱,希尔排序(缩小增量排序)
void ShellSort(int *array, size_t size)
{
	int gap = size;
	while (gap>1 )
	{
		gap = gap / 3 + 1;
		for (size_t i = gap; i < size; i++)
	  {
		int key = array[i];
		int end = i- gap;
		//找当前元素需要插入的位置
		while (end >= 0 && key < array[end])//end>0避免end越界
		{
			array[end + gap] = array[end];//往后搬移
			end -= gap;
		 }
		array[end + gap] = key;
	  }
		/*gap--;*/
	}
}
void display(int *array, int size)
{
	for (int i = 0; i < size; i++)
		cout << array[i] << " ";
	cout << endl;
}
void TestSort()
{
	int arr[] = { 9,5,5,6,8,2,3,1,7};
	int size = sizeof(arr) / sizeof(*arr);
	cout << "直接插入排序:";
     InsertSort(arr, size);
	 display(arr, size);
	 cout << "二分插入排序:";
	InsertSort_OP(arr, size);
	display(arr, size);
	cout << "希尔插入排序:";
	ShellSort(arr, size);
	display(arr, size);
}



### 希尔排序算法详解 #### 算法概述 希尔排序(Shell Sort),亦称为递减增量排序算法,是对插入排序的一种优化版本[^1]。该算法由Donald Shell于1959年提出,并在论文“A high-speed sorting procedure”中对其进行了详细的阐述[^3]。 #### 工作原理 希尔排序通过比较相隔一定间隔的元素来工作,这些间隔逐渐减少直到变为1。当间隔为1时,希尔排序即成为普通的插入排序。这种策略使得远距离的据可以更快地移动到接近其最终位置的地方,从而提高了整体性能[^4]。 #### 时间复杂度分析 尽管具体的渐近时间复杂度取决于所使用的间隔序列,但在最坏情况下,希尔排序的时间复杂度通常优于简单的插入排序。对于某些特定的选择间隔序列,平均情况下的表现甚至能够达到接近\( O(n \log n) \)。 #### 实现细节 以下是使用Python编写的希尔排序的具体实现: ```python def shell_sort(arr): n = len(arr) gap = n // 2 while gap > 0: for i in range(gap, n): temp = arr[i] j = i while j >= gap and arr[j - gap] > temp: arr[j] = arr[j - gap] j -= gap arr[j] = temp gap //= 2 if __name__ == "__main__": test_array = [64, 34, 25, 12, 22, 11, 90] print("原始组:", test_array) shell_sort(test_array) print("排序后的组:", test_array) ``` 这段代码展示了如何利用逐步缩小的间隔来进行多次部分有序化的操作,最后完成整个列表的完全排序过程[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值