排序

常见的排序算法
在这里插入图片描述一:插入排序

直接插入排序:[0,end]有序,将end+1 插入到区间[0,end],保持有序。
举例如图所示:

数组为 [ 3,4,2,1,6,0,9,5 ]
在这里插入图片描述实现代码:

// 插入排序
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1;i++)
	{
		//将end+1 往有序区间[0,end]中插入,使其保持有序
		int end = i;
		int insert = a[end + 1];

		while (end >= 0)
		{
			if (insert < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		//将insert放在[end+1]位置
		a[end + 1] = insert;
	}
}

希尔排序:先选定一个整数gap,把待排序文件中所有记录分成组,所有距离相同的为一组,并对组进行排序。然后,取,重复上述分组和排序的工作。当到达gap==1时,所有记录在统一组内排好序。

数组为:[ 9,8,7,6,5,4,3,2,1,0 ]
在这里插入图片描述实现代码:

// 希尔排序
void ShellSort(int* a, int n)
{
	//1. gap>1是预排序,让数组接近有序
	//2. gap==1,就相当于直接插入排序,保证有序
	int gap = n;
	
	//多组并排
	while (gap > 1)
	{
		gap = gap / 3 + 1;      //+1保证了最后一次gap一定是1

		//gap==1,最后一次相当于直接插入排序
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int insert = a[end + gap];
			while (end >= 0)
			{
				if (insert < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = insert;
		}
	}
}

二:选择排序

直接选择排序:在元素集合array[i]–array[j]中选最小和最大的数据元素,若它不是这组元素中的第i个和第j个,则将它们和第i,第j位置元素交换,在剩余的array[i+1]–array[j-1]集合中,重复上述步骤,直到集合剩余1个元素
在这里插入图片描述实现代码:

// 选择排序
void SelectSort(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini;
		int maxi;
		mini = maxi = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] > a[maxi])
				maxi = i;
			if(a[i] < a[mini])
				mini = i;	
		}
		Swap(&a[begin], &a[mini]);

		//如果begin和maxi位置重叠,需要对maxi进行修正
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}

堆排序:需要注意的是排升序要建大堆,排降序建小堆。

实现代码:

// 堆排序
//向下调整算法
void AdjustDown(int* a, int n, int root)
{
	int parent = root;
	int child = parent * 2 + 1;

	while (child < n)
	{
		//找出左右孩子中大的数据给child
		if (child + 1< n && a[child + 1] > a[child])
			++child;

		//如果child位置数据大于parent位置数据,进行交换
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
	
}
//时间复杂度:O(N*logN)
void HeapSort(int* a, int n)
{
	//建大堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n , i);
	}

	int end = n - 1;
	//用建大堆算法排升序
	for (end = n - 1; end >= 0; --end)
	{
		//将堆顶数据与a[end]位置数据进行交换
		Swap(&a[end], &a[0]);

		//将前 end 个数据继续用向下调整算法进行建大堆
		AdjustDown(a, end, 0);
	}
}

为什么不能排升序建小堆?

如果用建小堆,选出最小的数据,再次建堆选出次小的,整个排出来的时间复杂度为O(N^2)。
通过建大堆,每次从堆顶选出最大数据,将其与堆内最后一个值进行交换,然后不将最后一个值看作堆里,堆的大小减1,再用向下调整算法调整为大堆,依次选出次小的,换堆内最后一个位置,再继续直到堆内数据为1个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值