冒泡排序和快速排序

基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

冒泡排序

这里写图片描述
冒泡排序是最常见的排序方法,思路也简单,时间复杂度是。它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。
在这里插入图片描述

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
void BubbleSort(int* arr, int n)//升序
{
	
	for (int i = 0; i < n-1; ++i)//n个数需要冒泡冒n-1趟
	{
		int flag = 0;//每趟开始之前flag置零
		for (int j = 0; j < n-1-i; j++)
		{
			if (arr[j]>arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 1;
			}
		}
		if (flag == 0)//数组有序,无需再冒泡。
			break;
	}
}

测试段

void TestSort()
{
	int arr[] = {38,51926,49971,66};
	int len = sizeof(arr) / sizeof(int);
	BubbleSort(arr, len);
	for (int i = 0; i < len; i++)
		printf("%d ", arr[i]);
	printf("\n");
}
int main()
{
	TestSort();
	system("pause");
	return 0;
}

在这里插入图片描述
冒泡排序最好情况时间复杂度 O ( n ) O(n) O(n),冒泡排序最坏情况下时间复杂度 O ( n 2 ) O(n^{2}) O(n2)
冒泡排序空间复杂度 O ( 1 ) O(1) O(1)
冒泡排序是一种稳定的排序算法

快速排序的三种递归实现

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值key,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

左右下标法

在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<stdio.h>
//三数取中间值作为基准key
void MidThree(int*arr,int first,int end,int mid)
{
	if (arr[first] > arr[end])
		swap(arr[first], arr[end]);

	//arr[first]<=arr[end]
	if (arr[mid] < arr[first])
		swap(arr[first], arr[end]);
	else if (arr[mid] < arr[end])//arr[mid]>arr[mid]>arr[first]
		swap(arr[mid], arr[end]);
}
int Partion1(int*arr,int left,int right)//前begin找大,后end找小
{
	int mid = left + (right-left) / 2;
	if (right - left>2)
		MidThree(arr, left, right, mid);
		//首元素、尾元素、arr[mid]的中位数放到arr[end]位置

	int& key = arr[right];
	while (left < right)
	{
		while (left < right&&arr[left] <= key)
			++left;
		while (left<right&&arr[right] >= key)
			--right;

		if (left<right)
			swap(arr[left], arr[right]);
	}
	swap(arr[mid], key);
	return left;
}
void QuickSort(int* arr, int left, int right)
{
	if (left < right)
	{
		// 按照基准值将left和right标记区间划分成两部分
		int div = Partion1(arr, left, right);
		// 排列左半部分
		QuickSort(arr, 0, div - 1);
		// 排列右半部分
		QuickSort(arr, div + 1, right);
	}
}

测试代码

void TestSort()
{
	int arr[] = { 4,1,3,0,2,5,9,8,6,7 };
	int len = sizeof(arr) / sizeof(int);
	QuickSort(arr, 0, len);
	for (int i = 0; i < len; i++)
		printf("%d ", arr[i]);
	printf("\n");
}
int main()
{
	TestSort();
	system("pause");
	return 0;
}

在这里插入图片描述

前后下标法

在这里插入图片描述

  1. 定义变量cur指向序列的开头,定义变量prev指向cur的前一个位置。
  2. 当array[cur] < key时,cur和prev同时往后走,如果array[cur]>key,cur往后走,prev留在大于key的数值前一个位置。
  3. 当array[cur]再次 < key时,++prev!=cur时候,此时prev处于cur走过的路上,arr[prev]肯定是不小于key的数,交换cur与prev的值。
while (cur < right)
	{
		if (arr[cur] < key&&++prev != cur)
			swap(arr[cur], arr[prev]);
		++cur;
	}

每次交换之前的状态:

元素位置值特征
[0,prev]小于key
[prev+1,cur-1]大于key
cur小于key
int Partion2(int* arr, int left, int right)
{
	int mid = left + (right - left) / 2;
	if (right - left>2)
		MidThree(arr, left, right, mid);

	int key = arr[right];
	int cur = left, prev =  left - 1;
	while (cur < right)
	{
		if (arr[cur] < key&&++prev != cur)
			swap(arr[cur], arr[prev]);
		++cur;
	}
	swap(arr[right], arr[++prev]);
	return prev;
}

挖坑法

  1. 选取一个关键字(key)作为枢轴,一般取整组记录的第一个数/最后一个,这里采用选取序列最后一个数为枢轴,也是初始的坑位。
  2. 设置两个变量left = 0;right = N - 1;
  3. 从left一直向后走,直到找到一个大于key的值,然后将该数放入坑中,坑位变成了array[left]。
  4. right一直向前走,直到找到一个小于key的值,然后将该数放入坑中,坑位变成了array[right]。
  5. 重复3和4的步骤,直到left和right相遇,然后将key放入最后一个坑位。
    在这里插入图片描述
int Partion3(int* arr, int left, int right)
{
	int mid = left + (right - left) / 2;
	if (right - left>2)
		MidThree(arr, left, right, mid);

	int key = arr[right];

	while (left < right)
	{
		while (left < right && arr[left] <= key)
		{
			++left;
		}
		arr[right] = arr[left];
		while (left < right && arr[right] >= key)
		{
			--right;
		}
		arr[left] = arr[right];
	}
	arr[right] = key;
	return right;
}

递归快排优化

由于是递归程序,每一次递归都要开辟栈帧,当递归到序列里的值不是很多时,我们可以采用直接插入排序来完成,从而避免这些栈帧的消耗。

void QuickSort(int* arr, int left, int right)
{
	int len = right - left + 1;
	if (len < 5)
	{
		for (int start = left + 1; start <= right; start++)
		{
			int pos = start;
			int insert = arr[pos];
			while (pos>0 && arr[pos - 1] > insert)
			{
				arr[pos] = arr[pos - 1];
				pos--;
			}
			arr[pos] = insert;
		}
	}
	else
	{
		int div = Partion2(arr, left, right);
		QuickSort(arr, 0, div - 1);
		QuickSort(arr, div + 1, right);
	}
}

快排非递归

void QuickSortNotR(int* arr, int left, int right)
{
	assert(arr);
	stack<int> s;
	s.push(left);
	s.push(right);//后入的right,所以要先拿right
	while (!s.empty())//栈不为空
	{
		int right_ = s.top();
		s.pop();
		int left_ = s.top();
		s.pop();

		int index = Partion1(arr, left_, right_);
		if ((index - 1) > left_)//左子序列
		{
			s.push(left_);
			s.push(index - 1);
		}
		if ((index + 1) < right_)//右子序列
		{
			s.push(index + 1);
			s.push(right_);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值