再谈排序

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

void insert_sort(vector<int>& arr)
{
	/*
	* 注意稳定性的保护
	* 可以用折半优化比较次数,但是元素移动是没有办法的
	* 用链表存储的数据,虽然元素移动减少了,但是比较次数还是O(n^2)
	* 不过当元素基本有序时,链表的效率就很高;数组的效率也会得到提升
	*/
	int n = arr.size();
	for (int i = 1; i < n; i++)
	{
		if (arr[i - 1] > arr[i])
		{
			int key = arr[i];
			int j;
			for (j = i - 1; j >= 0 && arr[j] > key; j--)
				arr[j+ 1] = arr[j];
			arr[j + 1] = key;
		}
	}
}


void shell_sort(vector<int>& arr)
{
	/*
	* 希尔排序:基于插入排序优化(插入排序在元素基本有序时效率较高,那么我们缩小数组长度,让其经过一次遍历后的到基本有序,从而利用好这一特性)
	* 把待排序的数组,拆分成相距距离为d的视为一个组,对每个小组进行插入排序
	* 只适用于数组,不能用于链表,因为每次都要根据下标快速定位到下一个子表中,链表存储是无法做到的
	*/
	int n = arr.size();
	int d = n / 2;
	while (d >= 1) {
		for (int i = d; i < n; i++)//i++不用变   for (int i = 1; i < n; i++)
		{
			if (arr[i - d] > arr[i])             //if (arr[i - 1] > arr[i])
			{
				int key = arr[i];
				int j;
				for (j = i - d; j >= 0 && arr[j] > key; j-=d)    //减1都变成减d  for (j = i - 1; j >= 0 && arr[j] > key; j--)
					arr[j+ d] = arr[j];//从后往前把元素后移                         
				arr[j + d] = key;
			}
		}
		d /= 2;
	}
}

void bubble_sort(vector<int>& arr)
{
	/*具有稳定性,O(n^2)
	* 可以用于链表
	*/
	int n = arr.size();
	for (int i = 0; i < n-1 ; i++)//n-1趟
	{
		bool flag = false;
		for (int j = 1; j < n-i; j++)//把大的元素往后冒,每趟的元素都会减少,因为一趟会确定一个元素的顺序位置
		{
			if (arr[j] < arr[j - 1])
			{
				swap(arr[j], arr[j - 1]);
				flag = true;//说明本次遍历进行了交换
			}
		}
		if (flag)return;//如果一趟排序没有交换任何元素,说明数组已经有序 
	}
}


void merge(vector<int>& vec, int left, int mid, int right, vector<int>& temp)
{
	int i, j, k;
	for (i = left, j = mid, k = left; i < mid && j < right; k++)
	{
		if (vec[i] < vec[j])
			temp[k] = vec[i++];
		else temp[k] = vec[j++];
	}
	while(j < right)
		temp[k++] = vec[j++];
	while (i < mid)
		temp[k++] = vec[i++];
}

void merge_sort(vector<int>& vec,int left,int right,vector<int>& temp)
{
	if (right - left <= 1)
		return;
	int mid = (left + right) / 2;
	merge_sort(vec, left, mid, temp);
	merge_sort(vec, mid, right, temp);
	merge(vec, left, mid, right, temp);
	vec = temp;
}

int paration(vector<int>& vec, int left, int right)
{
	int key = vec[left];//把最左侧结点提出,下面while先去移动right,找小于key的
	while (left < right)
	{
		while (left < right && vec[right] >= key) right--;
		vec[left] = vec[right];
		while (left < right && vec[left] <= key) left++;//在上面相当于right此时被提出
		vec[right] = vec[left];
	}
	vec[left] = key;//给枢轴位置赋key
	return left;
}

void qsort(vector<int>& vec,int left,int right)
{
	/*时空复杂度都和递归栈深度相关
	* 最好情况O(nlogn),一般也是这样
	* 最坏情况,每次qsort得到的枢轴将数都只能划走一个元素,就成了单边树
	* 此时递归深度就是n,时间复杂度就是O(n^2)
	* 不稳定
	*/
	if (right - left < 1)
		return;
	int pviot = paration(vec,left,right);
	qsort(vec,left, pviot-1);
	qsort(vec,pviot + 1, right);
	
}

//[ left, right]
//void qsort(vector<int>& arr,int left ,int right)
//{
//	int i = left;
//	int j = right;
//	int key = arr[right];
//	while (i < j)
//	{
//		while (arr[i] < key)//小于枢轴key,指针i一直向后移动
//		{
//			i++;
//		}
//		while (arr[j] > key)//大于枢轴,指针j向前移动
//		{
//			j--;
//		}
//
//		//上面的两步都没有边界判断,会越界吗?
//		//不会,因为while的判断条件是arr[i] < key,只有小于才会移动,那么极限情况key刚好是最大值,
//		//i==right-1时就会移动到right,此时i继续+1,这时while判断就会失败因为两值相等,所以i就停在了right
//
//		if (i <= j)
//		{
//			//上面先移动i,故而最后情况是:i停在了一个大于等于key的值,j停在了一个小于等于key的值,此时交换两值
//			//每次都是i先移动,能不能让j先移动呢,是可以的,但是只有i<=j这才合法,才会交换
//			swap(arr[i], arr[j]); // i==j时,不用swap但是要i++,j--
//			i++;
//			j--;
//		}
//	}
//	
//	if (j > left)
//		qsort(arr, left, j);//上面在最后的i==j时,i和j都已近各自向前向后移动了,这里就不用区间-1
//	if (i < right)
//		qsort(arr, i, right);
//}

//void qsort(vector<int>& arr, int left, int right)//[left,right],极简快排
//{
//	int key = arr[right], i = left, j = right;
//	while (i < j)
//	{
//		while (arr[i] < key)i++;
//		while (arr[j] > key)j--;
//		if (i <= j)swap(arr[i++], arr[j--]);
//	}
//	if (j > left)qsort(arr, left, j);
//	if (i < right)qsort(arr, i, right);
//}

void choice_sort(vector<int>& arr)
{
	/*
	* 可用于链表,不稳定
	*/
	int n = arr.size();
	for (int i = 0; i < n - 1; i++)
	{
		int min_pos = 0;
		for (int j = i + 1; j < n; j++)
		{
			if (arr[min_pos] > arr[j])
				j = min_pos;
		}
		swap(arr[min_pos], arr[i]);
	}
}


void adjustdown(vector<int>& arr, int parent, int end)
{
	int child = parent * 2 + 1;
	while (child < end)
	{
		if (child + 1 < end && arr[child + 1] > arr[child])
			child++;
		if (arr[parent] < arr[child])
			swap(arr[parent], arr[child]);
		parent = child;
		child = parent * 2 + 1;
	}
}
void heap_sort(vector<int>& arr)
{
	/*
	* 堆结构:在完全二叉树中,根 <= 左、右(小根堆)
	* 把所有非叶子结点都检查一遍,是否满足大根堆的要求,如不满足,进行调整
	* 调整要调到叶节点才算结束
	* 不稳定,O(nlogn)
	*/
	int n = arr.size();
	for (int root = n / 2; root >= 0; root--)
		adjustdown(arr, root, n - 1);
	int end = n - 1;
	while (end > 0)
	{
		swap(arr[end], arr[0]);
		adjustdown(arr, 0,end);
		end--;
	}
}


int main()
{
	vector<int> vec{ 98, 2, 123, 435, 1, 5, 62, 12, 634, 5, 9, 999 };
	//shell_sort(vec);
	auto temp = vec;
	merge_sort(vec, 0, vec.size(), temp);
	//qsort(vec, 0, vec.size()-1);
	heap_sort(vec);
	//bubble_sort(vec);
	for_each(vec.begin(), vec.end(), [](int x) {cout << x << " "; });
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值