IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 手撕快排(总结) -> 正文阅读

[数据结构与算法]手撕快排(总结)

  • 快排、堆排、归并排序
  • 链表快排(区分允许用值交换和不允许用值交换两种情况)
  • 非递归快排要掌握
  • 快排时间复杂度的推导过程?
  • 写出来后,也要把下面这几个点考虑下 - 时间复杂度计算 - 控件复杂度计算 - 轴点随机取值 - 为什么与轴点相等也要换位置

快排思路

  • 随便找一个数作为基准数6
  • 初始状态下,数字6在序列的第1位
  • 先从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换他们。这里可以用两个变量i和j,分别指向序列最左边和最右边。(i和j称为哨兵)
    在这里插入图片描述
  • 首先哨兵j开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵j先出动,这一点非常重要
  • 哨兵j的使命就是要找小于基准数的数,而哨兵i的使命就是要找大于基准数的数,直到i和j碰头为止
    在这里插入图片描述
    -哨兵i和哨兵j相遇于3,则将基准数6和3进行交换。
  • 现在基准数6已经归位,此时我们已经将 将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放在6的左边,接下来还需要分别处理这两个序列。

复杂度

快速排序的时间复杂度为:
在这里插入图片描述

快排实现

递归版本快排

//快速排序(从小到大)
void quickSort(int left, int right, vector<int>& arr)
{
	if(left >= right)
		return;
	int i, j, base, temp;
	i = left, j = right;
	base = arr[left];  //取最左边的数为基准数
	while (i < j)
	{
		while (arr[j] >= base && i < j)
			j--;
		while (arr[i] <= base && i < j)
			i++;
		if(i < j)
		{
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	//基准数归位
	arr[left] = arr[i];
	arr[i] = base;
	quickSort(left, i - 1, arr);//递归左边
	quickSort(i + 1, right, arr);//递归右边
}

非递归版本快排:
1.用栈集合存放左右下标
2.用一个方法来得出中下标位置
3.判断中下标的左右区间
4.回到步骤1循环这几步操作,知道栈为空,则排序完成。

#include <iostream>
#include <stack>
using namespace std;
 
//划分算法
int Partition( int a[], int low, int high )
{
	//假设每次都以第一个元素作为枢轴值,进行一趟划分:
	int pivot = a[low];
	 
	while( low<high )
	{
		while( low<high && a[high]>=pivot )
		--high;
		a[low] = a[high];  //停下来做交换 
		while( low<high && a[low]<=pivot )
		++low;
		a[high] = a[low];  //停下来做交换 
	}
	
	a[low] = pivot;  //pivot的最终落点 
	return low;
}
 
//非递归快排
void QuickSort(int a[], int left, int right)
{
	//手动利用栈来存储每次分块快排的起始点
	//栈非空时循环获取中轴入栈
	stack<int> s;
	if( left<right )
	{
		int boundary = Partition(a,left,right);
		
		if( boundary-1>left ) //确保左分区存在 
		{
			//将左分区端点入栈 
			s.push(left);
			s.push(boundary-1);
		}
		if( boundary+1<right ) //确保右分区存在 
		{
			s.push(boundary+1);
			s.push(right);
		}
		
		while( !s.empty() )
		{
			//得到某分区的左右边界 
			int r = s.top();
			s.pop();  
			int l = s.top();
			s.pop();
			
			boundary = Partition(a,l,r);
			if( boundary-1>l ) //确保左分区存在 
		    { 
			    //将左分区端点入栈 
		    	s.push(l);
		    	s.push(boundary-1);
	    	}
		    if( boundary+1<r ) //确保右分区存在 
	     	{
	 	    	s.push(boundary+1);
	    		s.push(r);
	    	}
		}
	}
}
 
int main()
{
	int a[5] = { 4, 1, 5, 3, 2 };
	int left = 0, right = 4;
	QuickSort(a,left,right);
	
	//输出,检验结果 
	for( int i=0; i<5; ++i )
	{
		cout << a[i] << " ";
	}
	
	cout << endl;
}

point1

当基准数选择最左边的数字时,那么就应该先从右边开始搜索;当基准数选择最右边的数字时,那么就应该先从左边开始搜索。不论是从小到大排序还是从大到小排序!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 15:58:58  更:2021-12-23 15:59:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:31:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码