分治法 —— 快速排序(递归,迭代,非递归)
快速排序
快速排序三种方法,你值得参考!!!
- 快速排序
- 1,快速排序之递归
- Code 递归
- 2,快速排序之迭代
- Code 迭代
- 3,快速排序之非递归
- Code 非递归
- 4,结语
快速排序在所有排序中基本上速度是最快的啦
(前提是基准元素要选的好,没选好基准元素很可能变为冒泡排序)
快速排序算法思想是分治策略,但可以有多种手段来实现
1,快速排序之递归
其实快速排序之递归是传统的快速排序。为什么说是传统的呢? 大部分的快速排序无论是在教材上还是在一些博客上基本采用递归分治来实现。因为此方法比较好懂
递归快速排序一般都是两个游标 i 和 j , i在左,j在右
i 往右移发现a[i] 大于 pivot 进行交换,j往左移发现a[j]小于 pivot 进行交换。直到i不小于j才推出,此时第一轮循环完毕,左右两边基本有序。接着分治进行左右两个part使之有序,最终整个数组有序
废话不多说,直接上代码的啦!
大部分地方都有代码注释应该都容易理解的,哈哈哈。
Code 递归
#include <cstdio>
#include <iostream>
using namespace std;
//递归方式
//-----------------------------------------------------------------------
void Swap(int& a, int& b)//元素的交换,注意用引用,否则用指针
{int temp = a;a = b;b = temp;
}
void QuickSort1(int s[],int low, int high)
{if (low >= high) return ;//递归退出int pivot = s[low];//元素选择不恰当,时间复杂度会加大//当然这里仅仅只讲解快速排序的写法,基元素的选择也可以优化,此处不进行讲解演示int i = low, j = high;while (i < j){while (s[j] > pivot) j--;Swap(s[j], pivot);//j向左移发现有小于pivot的值,交换while (s[i] < pivot) i++;Swap(s[i], pivot);//i向右移发现有大于pivot的值,交换}QuickSort1(s, low, i - 1);//进入左边part再进行快速排序QuickSort1(s, j + 1, high);//进入右边part再进行快速排序
}//-----------------------------------------------------------
//QucikSort2在QuickSort1的基础上稍微优化一下,减少交换的次数
//每次交换a[i] 和 a[j] , 最后将a[i] 或 a[j] 与pivot交换即可
//大大减少交换次数
/*
void QuickSort2(int s[],int low, int high)
{if (low >= high) return ;//递归退出int pivot = s[low];int i = low, j = high;while (i < j){while (i < j && s[j] > pivot) j--;while (i < j && s[i] <= pivot) i++;Swap(s[i], s[j]);//找到i和j 然后交换 a[i] 和 a[j]}Swap(s[low], s[i]);//最后和pivot交换//Swap(pivot, s[i]);注意不要和pivot变量交换哟,那仅仅只是改变pivot的值//我们需要改变pivot值得所在位置上的值,即是s[low] ,明白吗?QuickSort2(s, low, i - 1);QuickSort2(s, j + 1, high);
}
*/
//------------------------------------------------------------------------------
int main()
{//int a[9] = {12,24,5,18,30,36,58,42,39};int a[9] = {30, 24, 5, 58, 18, 36 , 12, 42, 39};for (int i = 0; i < 9; i++)printf("%d ", a[i]);printf("\n\n-----------------------------------\n\n");QuickSort1(a, 0, 8);//QuickSort2(a, 0, 8);for (int i = 0; i < 9; i++)printf("%d ", a[i]);return 0;
}
2,快速排序之迭代
仅用一个循环(for 或 while) 来完成快速排序中的基本有序,每次返回mid 值。此方法需要稍稍理解一下,没有递归快排好懂呀!但是我认为你可以看懂的,因为我讲的很清楚啦!
我们来看此段核心代码,只用一个循环来找出中间值,大大的提高程序的效率!!!
int Partition1(int r[], int low, int high)
{int i, j, pivot = r[high];for (j = low, i = low - 1; j < high; j++){//i 始终在j的后面,用于交换if (r[j] < pivot){i = i + 1;Swap(r[i], r[j]);}}Swap(r[i + 1], r[high]);return i + 1;
}
以数组{30, 24,5, 58, 18, 36 , 12, 42, 39}为例
经过一次循环中间不断进行交换使之变为 {30, 24, 5, 18, 36 , 12, 39, 42, 58},在39左边数据都比39小,39右边数据比39大,基本有序!!!
此段核心代码需要结合例子画图理解,裸想有点难度的喲!下面的图片很好的阐述如何使一个数组基本有序,并返回i + 1, 即mid的值
Code 迭代
#include <cstdio>
#include <iostream>
using namespace std;void Swap(int& a, int& b)
{int temp = a;a = b;b = temp;
}
//我们重点来看partition1
int Partition1(int r[], int low, int high)
{int i, j, pivot = r[high];for (j = low, i = low - 1; j < high; j++){if (r[j] < pivot){i = i + 1;Swap(r[i], r[j]);}}Swap(r[i + 1], r[high]);return i + 1;
}
//----------------------------------------------------------
//这里采用pivot 为s[low] ,并使用一次循环使之数组基本有序并返回中间元素的位置
/*
int Partition2(int r[], int low, int high)
{int i, j, pivot = r[low];for (j = low + 1, i = low; j <= high; j++){if (r[j] < pivot){i = i + 1;Swap(r[i], r[j]);}}Swap(r[i], r[low]);return i;
}*/
//------------------------------------------------------------------
void QuickSort(int R[], int low, int high)
{int mid;if (low < high){mid = Partition1(R, low, high);//Partition1函数用来返回基本有序后的数组的中间基元素的位置(下标)QuickSort(R, low, mid - 1);//递归进入左边partQuickSort(R, mid + 1, high);//递归进入右边part}
}
int main()
{//int a[9] = {12,24,5,18,30,36,58,42,39};int a[9] = {30, 24,5, 58, 18, 36 , 12, 42, 39};for (int i = 0; i < 9; i++)printf("%d ", a[i]);printf("\n\n-----------------------------------\n\n");QuickSort(a, 0, 8);for (int i = 0; i < 9; i++)printf("%d ", a[i]);return 0;
}
3,快速排序之非递归
其实非递归也很好实现的,学过数据结构的同学应该知道大部分的递归是可以用栈来表示的,快速排序的非递归的表示也是如此的。
主要采用一个栈来保存low(left) 和 high(right) ,不断进行入栈 和出栈操作即可实现!!!
Code 非递归
#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
void Swap(int& a, int& b)
{int temp = a;a = b;b = temp;
}
int Partition(int r[], int low, int high)
{int i = low, j = high, pivot = r[low];while (i < j){while (i < j && r[j] > pivot)//i < j 防止重复的执行交换操作j--;if (i < j)Swap(r[i++], r[j]);//左边右移一位while (i < j && r[i] <= pivot)i++;if (i < j)Swap(r[i], r[j--]);}return i;
}
void QuickSort3(int s[],int low, int high)
{stack<int> st;//声明一个栈st.push(low);st.push(high);//入栈while (!st.empty())//栈不为空时{int right = st.top();st.pop();//出栈右边界点int left = st.top();st.pop(); //出栈左边界点int mid = Partition(s, left, right);if (left < mid - 1)//左part的两个边界点入栈{st.push(left);st.push(mid - 1);}if (right > mid + 1)//右part的两个边界点入栈,注意和左part的入栈顺序不一样{st.push(mid + 1);st.push(right);}}
}
int main()
{//int a[9] = {12,24,5,18,30,36,58,42,39};int a[9] = {30, 24,5, 58, 18, 36 , 12, 42, 39};for (int i = 0; i < 9; i++)printf("%d ", a[i]);printf("\n\n-----------------------------------\n\n");QuickSort3(a, 0, 8);for (int i = 0; i < 9; i++)printf("%d ", a[i]);return 0;
}
4,结语
快速排序总的来说采用的是分治策略,但实现的方式多种多样。此处给出三种实现的方式。事实上也是大同小异,掌握其中一种即可,但个人仍建议掌握三种呀!毕竟技多不压身呀,哈哈哈!
分治法 —— 快速排序(递归,迭代,非递归)相关推荐
- 快速排序和归并排序中一趟的理解(递归和非递归)
引:2019年408中数据结构一道考察快速排序的选择题 答案:D 定位:这道题在考察快速排序中一趟的概念.注意,基本的冒泡,插入,选择排序的一趟概念很容易理解, 接下来我们要讨论的是递归排序算法中(本 ...
- C#实现(递归和非递归)快速排序和简单排序
C#实现(递归和非递归)快速排序和简单排序 本人因为最近工作用到了一些排序算法,就把几个简单的排序算法,想冒泡排序,选择排序,插入排序,奇偶排序和快速排序等整理了出来,代码用C#代码实现,并且通过了测 ...
- 算法之快速排序(递归和非递归)
快速排序的两种实现方式.递归和非递归 1 package com.ebiz.sort; 2 3 import java.text.SimpleDateFormat; 4 import java.uti ...
- python快速排序递归与非递归
快速排序递归与非递归python 写在前面 快速排序的递归函数 快排的切分函数 快排的非递归函数 完整的源代码 写在前面 众所周知,快速排序相对于选择排序,插入排序,冒泡排序等初级排序有着天然的优势. ...
- python创建树结构、求深度_数据结构-树以及深度、广度优先遍历(递归和非递归,python实现)...
前面我们介绍了队列.堆栈.链表,你亲自动手实践了吗?今天我们来到了树的部分,树在数据结构中是非常重要的一部分,树的应用有很多很多,树的种类也有很多很多,今天我们就先来创建一个普通的树.其他各种各样的树 ...
- 二叉树的遍历-递归与非递归 - 海子
二叉树的遍历-递归与非递归 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方 ...
- 【恋上数据结构】递归(函数调用过程、斐波那契数列、上楼梯、汉诺塔、递归转非递归、尾调用)
递归(Recursion) 什么是递归? 函数的调用过程(栈空间) 函数的递归调用过程 递归实例分析(1 + 2 + 3 + ... + 100 的和) 递归的基本思想.使用套路 斐波那契数列 fib ...
- 二叉树的遍历(递归、非递归)
背景 二叉树是一种很基本的数据结构.很多地方能看到它的身影,比如大名鼎鼎的霍夫曼编码(好了,别问我再比如了,见识浅薄,真不知道更多了...)它的结构很简洁.巧妙. 本文讨论二叉树的常见遍历方式的代码实 ...
- C++实现二叉树 前、中、后序遍历(递归与非递归)非递归实现过程最简洁版本
本文并非我所写,是复制的该链接中的内容: 最近学习二叉树,想编程实现递归和非递归的实现方式: 递归的方式就不说了,因为大家的递归程序都一样:但是对于非递归的实现方式, 根据这几天的查阅资料已看到差不多 ...
最新文章
- 关于TVM的点滴记录
- 这里有最全的k8s初学者指南!!!
- 顺序三元组 java_三元组顺序结构实现稀疏矩阵相加,行序优先(Java语言描述)
- 宏与内联(inline)的区别(转载)
- python全栈开发优势_Python全栈开发多少钱?学Python价格贵吗?
- [设计模式] ------ 单例模式
- ASP.NET事件顺序如下所示
- 随机森林的原理及Python代码实现
- Mysql 引优化分析
- mysql长连接_mysql.connector 数据库长连接
- 「leetcode」104559:求树的最大深度
- 十九、RF接口测试汇总(一)
- bottleneck resnet网络_ResNet网络结构分析
- 用 Python 分析韦德职业生涯数据
- 37岁的老大叔零基础学python,来点鼓励吧
- 嵌入式设备时间同步管理
- 微信小程序页面跳转,url传参参数丢失问题
- 单片机产生可调方波(c语言),为什么我用单片机做的频率可调的方波输出会有尖刺,而且会断...
- 电脑用js调用QQ客服聊天 阿星小栈
- qlv,qsv,kux格式转换成MP4格式软件
热门文章
- vscode配置php运行环境以及xdebug
- 《歌剧魅影》(Phantom of the Opera)
- android 7.0关机动画,Android 修改系统关机动画的实现
- kicad最小布线宽度默认是多少_CABLExpress发布了最新的光纤布线最佳实践指南
- node命令与切换node版本
- [MEM]综合能力考试-数学知识点
- Python第六周作业
- 重庆SEO优化:网站通过SEO优化会有哪些好处以及【SEO优化】 深度了解蜘蛛spider抓取原理-专业SEO技术教程
- {“errcode“:48001,“errmsg“:“api unauthorized, hints: [ req_id: xxxxxxx]“}
- 微信小程序----App生命周期