排序相关实现--选择--冒泡排序--堆排序--快速排序

插入排序

在有序序列中插入一个值(tmp),(只有一个数据也是有序的),从有序序列的末端开始比较,比它小,就把这个数据往后放,依次去比,直到比到第一个数。

走完一趟 有序数组的大小就会增长一个。

void InsertSort(vector<int>& a)
{
	//[0,end]是有序的 现在插入的是 end+1这位数据
	//从后向前依次比较 查看插入位置

	for (int i = 0; i < a.size() - 1; i++)
	{
		//单趟
		int end=i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

希尔排序

由于插入排序在数据接近有序下的时间复杂是很低的,所以采用预排序,干涉一下数据。将数据每间隔gap个分为一组,先将这些数据采用插入排序。然后最后再使用gap==1时,即直接插入排序完成排序。

void ShellSort(vector<int>& a)
{
	int gap = a.size();
	while (gap > 1)
	{
		gap = gap / 3 + 1;//保证gap最少是1
		for (int i = 0; i + gap < a.size(); i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

选择排序

每次遍历选择一个最大的和一个最小的 插入在数组的begin处和end处,每插入一次之后begin++,end-- 直到二者相遇,则全部排序完成。

void SelectSort(vector<int>& a)
{
	if (a.empty()) return;
	int n = a.size();
	//begin 和 end是已经确定好排序的下标
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int mini = begin, maxi = end;
		for (int i = begin; i <= end; i++)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
			if (a[maxi] < a[i])
			{
				maxi = i;
			}
		}
		swap(a[begin], a[mini]);
		if (maxi == begin)
		{
			maxi = mini;
		}
		swap(a[end], a[maxi]);
		++begin;
		--end;
	}
}

堆排序

先将数据导入数组中,找到最后一个非叶节点,从它开始向下调整,自后向前。于是得到了一个大堆或者小堆。

这里以大堆为例。然后将堆顶的数据和堆尾的数据进行交换,并将堆尾的数据剔除排序区间。从堆顶再次进行向下调整,可以使得第二大的数称为堆顶。

再次交换堆顶和堆尾,并将堆尾的数据剔除排序区间...

//堆排序
void AdjustDown(vector<int>& a ,int length,int starti)
{
	//找孩子
	int child = starti * 2 + 1;
	//最差结果就是把最后一个数也调整了
	while (child < length)
	{
		if (child + 1 < length && a[child] < a[child + 1]) child++;
		if (a[child] > a[starti])
		{
			swap(a[child], a[starti]);
			starti = child;
			child = starti * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(vector<int>& a)
{
	int n = a.size();
	int start = (n - 1 - 1) / 2;//找到最后一个非叶节点
	//依次向下调整
	for (int i = start; i >= 0; i--)
	{
		AdjustDown(a,n,i);
	}
	//建成了一个大堆 要弄成升序
	int end = n - 1;
	while (end > 0)
	{
		swap(a[0], a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

冒泡排序

跟前一个比 你比我大 咱俩就交换 每过一轮就有一个当前的最大的值被换到数列尾,那么就可以少遍历一次。

void BubbleSort(vector<int>& a)
{
	int n = a.size();
	for (int j = 0; j < n - 1; j++) //轮次 4个数最多走三轮 剩下一个就自己确定了
	{
		int change = false;
		for (int i = 1; i < n - j; i++)
		{
			if (a[i-1] > a[i])
			{
				swap(a[i - 1], a[i]);
				change= true;
			}
		}
		if (!change) break; //如果一轮遍历下来 没有交换 就证明已经有序了
	}
}

快速排序

[left,right] 是一个左闭右闭区间

void QuickSort(int arr[], int left, int right)
{
	if (left >= right) return;
	int key = arr[(left + right) / 2];//区间中间的那个值做key
	int i = left - 1;
	int j = right + 1;
	while (i < j)
	{
		//左找大
		do
		{
			i++;
		} while (arr[i] < key);
		

		//右找小
		do
		{
			j--;
		} while (arr[j]>key);

		if (i < j)
		{
			swap(arr[i], arr[j]);
		}
	}
	QuickSort(arr, left, j);
	QuickSort(arr, j+1, right);
}

其他版本

// 快速排序hoare版本
void PartSort1(int* a, int left, int right)
{
	int begin = left; int end = right;//left 和 right会随着程序改变,找两个变脸记录初始位置
	if (begin >= end)
	{//区间不存在 就不用排序了
		return;
	}
	//左边做key 右边向左找小,左边向右找大 
	int keyi = left; 
	while (left < right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		//到达此位置 表示找到了大和小
		swap(&a[left], &a[right]);

	}
	//到达此位置 表示左右相遇 a[left] 去和a]keyi]交换
	swap(&a[left], &a[right]);
	keyi = left;// xxxx keyi xxxx
	PartSort1(a, begin, keyi - 1);
	PartSort1(a, keyi + 1, end);
}
// 快速排序挖坑法

void PartSort2(int* a, int left, int right)
{
	int begin = left; int end = right;//left 和 right会随着程序改变,找两个变脸记录初始位置
	if (begin >= end)
	{//区间不存在 就不用排序了
		return;
	}
	int holei= left;//坑的坐标
	int key = a[begin];//存储坑的数据
	while (left < right)
	{
		while (left < right && a[right] >= a[holei])
		{
			right--;
		}
		//自身成为洞
		a[holei] = a[right];//洞的数据不重要,直接赋值即可
		holei = right;//更新洞的坐标
		while (left < right && a[left] <= a[holei])
		{
			left++;
		}
		a[holei] = a[left];
			holei = left;
		//到达此位置 表示找到了大和小
		swap(&a[left], &a[right]);

	}
	//到达此位置 表示左右相遇 a[left] 去和a]keyi]交换
	a[left] = key;//存储的第一个洞的值
	holei = left;// xxxx holei xxxx
	PartSort1(a, begin, holei - 1);
	PartSort1(a, holei + 1, end);
}
// 快速排序前后指针法

void PartSort3(int* a, int left, int right)
{
	int begin = left; int end = right; int keyi = begin;
	if (begin <= end)
	{
		return;
	}
	// prev cur   a[cur]和a[keyi]比较 小于时 prev++ 交换 cur 和 prev.cur++;
	
	int prev = begin; int cur = prev + 1;
	while (cur <= end)
	{
		if (a[cur] < a[keyi])
		{
			++prev;
			swap(&a[cur], &a[prev]);
			++cur;
		}

	}
	//cur越界了
	swap(&a[prev], &a[keyi]);
	keyi = prev;// xxxx keyi xxxxx
	PartSort3(a, begin, keyi - 1);
	PartSort3(a, keyi + 1, end);   
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值