直接插入排序和希尔排序

91 阅读2分钟

直接插入排序:

它的本质仍然是对撞指针,只不过首指针固定在首位置不动,尾指针end依次--,让前end个数有序

想法:定义一个end变量=0,end从0++到n(数组长度)

(1)定义一个temp=a[end+1]:(又称岗哨)(反正理解为一个特殊的值即可)

2)在升序的情况下:如果a[end]>temp:即a[end]>a[end+1]

那么我们就要使a[end+1]=a[end]:即后面一个数的值被前面一个数的值覆盖了

但是不用担心,我们已经用temp存储了a[end+1]的值

我们说过了:这个排序的想法是让前end个数有序

(3)所以作为尾指针,它要向左移动,即end--

接着重复(2)即可

如果遇到a[end]<a[end+1]的情况,我们就不需要end--了,break跳出循环

注意此时整个数列中并没有temp的值,

(4)我们需要将a[end]=temp,将temp还原到它的对应位置

 

#include<stdio.h>
void TestInsertsort();
void printarray(int *a, int n);
void Insertsort(int *a,int n);
void TestInsertsort()
{
	int a[] = { 9,5,3,2,4,1,6,7,8,10 };
	int n = sizeof(a) / sizeof(a[0]);
	Insertsort(a, n);
	printarray(a, n);
}
void Insertsort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
        
		int end = i;//尾指针
		int temp = a[end + 1];//岗哨
		while (end >= 0)
		{
			if (a[end] > temp)//如果前一个数比后一个数大,则前一个数的值覆盖后一个数的值
			{
				a[end + 1] = a[end];
				end--;
			}
			else//反之,break,跳出循环
			{
				break;
			}
		}
		a[end+1] = temp;//最后还原
	}
}
void printarray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}
int main()
{
	TestInsertsort();
	return 0;
}

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

希尔排序:

想要理解为什么有希尔排序,我们就得先理解透直接插入排序:

直接插入排序的最好情况:全是升序:时间复杂度仅为O(N)

因为根本没有交换的过程(都排好了,不需要交换了):外层只有一个for循环

最坏的情况:全是降序:时间复杂度为O(N^2)

因为每一个数,几乎都需要交换一个数组的长度

那么为了优化:我们是不是可以将数组先进行预处理?

也就是将数组先粗略排成类似有序(很重要!)

怎么做呢?:希尔这个大神找到了gap

gap是间隔,也就是说,它让间隔为gap的数组元素有序,比如这里的gap=3

 将数组分为了三部分:

再将这三部分分别使用直接插入排序,因为数组此时很短,所以效率会很高

 此时就完成了一次粗略的类似排序

这时我们将gap=gap/2——即gap=2

 再对这两部分进行直接插入排序:由于是接近有序且短:所以效率会变高

 接着gap=gap/2——即gap=1,由于此时已经非常接近有序,用直接插入排序即可完成

#include<stdio.h>
void ShellSort(int* a, int n);
void TestShellSort();
void printarray(int* a, int n);
void TestShellSort()
{
	int a[] = { 9,7,5,3,1,2,4,6,8,10 };
	int n = sizeof(a) / sizeof(a[0]);
	ShellSort(a, n);
	printarray(a, n);
}
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 2;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int temp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > temp)
				{
					a[end + gap] = a[end];
					end = end - gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = temp;
		}
	}
}
void printarray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}
int main()
{
	TestShellSort();

	return 0;
}

发现了吗?

希尔排序本质上就只是将直接插入排序的间隔1改为了gap

并且让gap=gap/2,并在最外层加上了gap的循环

看似一个很简单的想法:在测试一万个数据的时候

希尔排序的运行时间是直接插入排序的0.01倍: