0
点赞
收藏
分享

微信扫一扫

【八大排序之插入和选择排序】

笙烛 2022-09-24 阅读 241

 写在前面

 

 

 

目录

 

 写在前面

1 插入排序

1.1 直接插入排序

1.2 希尔排序

 2 选择排序

2.1 直接选择排序

2.2 堆排序


 

1 插入排序

1.1 直接插入排序

基本思想:

注意事项:

具体代码:

void InsertSort(int* a, int sz)//最好情况是O(N)
{
	for (int i = 0; i < sz - 1; i++)
	{
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (a[end] > tmp)//降序就变成<
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}

		}
		a[end + 1] = tmp;
	}
}

1.2 希尔排序

基本思想:

 注意事项:

 具体代码:

void ShellSort(int* a, int sz)
{
	int gap = sz;
	while (gap)
	{
		gap /= 2;
		for (int i = 0; i < sz - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}

			}
			a[end + gap] = tmp;
		}
	}
}

 我们可以测试一下直接插入排序与希尔排序的性能对比:

 由上图可知当排10W个数据时希尔排序的效率时直接插入排序的几百倍,数据越多,它们之间的差距只会越来越大。


 2 选择排序

2.1 直接选择排序

基本思想:

 直接选择排序的思想很简单,代码写起来也比较容易,这里就直接上具体代码:

void SelectSort1(int* a, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz; i++)
	{
		int k = i;
		for (j = i + 1; j < sz; j++)
		{
			if (a[k] > a[j])
			{
				k = j;
			}
		}
		Swap(&a[i], &a[k]);
	}
}

这里还可以用双下标的方法优化一下直接选择排序,让其效率比第一种要高一些,但是时间复杂度还是O(N^2),具体代码:

void SelectSort2(int* a, int sz)
{
	int begin = 0;
	int end = sz - 1;
	while (begin < end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] < a[mini])
			{
				mini = i;
			}
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		if (a[begin] == a[maxi])
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		begin++;
		end--;
	}
}

2.2 堆排序

具体代码(以建大堆为例):

void AdjustDown(int* a, int sz, int root)
{
	int parent = root;
	int child = parent * 2 + 1;
	while (child < sz)
	{
		if (a[child + 1] > a[child] && child + 1 < sz)
		{
			child++;
		}

		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

 

 但如果左右子树并不是大堆(小堆)那应该怎么办呢?

我们的处理方法是从倒数第二排的非叶子结点(也就是最后一个元素的父亲)开始建堆,直到第一个元素为止,具体代码如下:

for (int i = (sz - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, sz, i);
	}

这样就完成了建堆,那么建堆的时间复杂度是多少呢?

这里我们可以来计算一下:

然后用错位相减法就可以得出:t(n)=2^h-h-1; 由于是完全二叉树h=log(i+N) (以2为底),

带入得t(n)=N-log(N+1)   当N区域无穷大得时候 t(n)=N; 故其建堆的时间复杂度为O(N).

具体代码:

 我们来看看这四种排序的效率对比:

 由图可以直观看出堆排序和希尔排序的效率比较高,直接插入和直接选择的效率较低。


 好了,今天的分享就到这里了,如果对你有帮助的话能不能支持一下博主呢?

 

举报

相关推荐

0 条评论