常用排序算法的总结以及编码(Java实现)
常用排序算法的总结以及编码(Java实现)
本篇主要是总结了常用算法的思路以及相应的编码实现,供复习的时候使用。如果需要深入进行学习,可以使用以下两个网站:
- GeeksForGeeks网站用于学习相应的原理以及编码
- Visualgo网站可以查看各种排序算法的动图,容易加深理解
冒泡排序
步骤
冒泡排序主要是通过依次比较相邻的两个元素,慢慢的将最大或者最小的元素“浮”出来。
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
编码实现
- /**
- * 最普通的冒泡排序算法
- * @param arr
- */
- public static void bubbleSort1(int[] arr){
- for (int i = 0; i < arr.length; i++) {
- // 在进行了第 i 次比较以后,最大的数据在 arr.length-i 处
- // 这个点相当于是个终点--在这个点以后的数据,都不需要在进行比较了,因为这个点以后的数据都已经排序过了
- for (int j = 1; j < arr.length - i; j++) {
- // 如果前面的数字比较大,将他移到后面去
- if(arr[j-1] > arr[j]){
- swap(arr,j-1,j);
- }
- }
- }
- }
- /**
- * 加上了flag的冒泡排序
- * 对于一个大部分数据已经排序了数组,则不需要进行大量的比较以及交换。
- * 那么可以设置一个flag,如果这个flag为flase,即没有产生交换,那么就意味着排序已经完成了。
- * @param arr
- */
- public static void bubbleSort2(int[] arr){
- // 初始化这个flag
- boolean flag = true;
- // 需要进行比较的边界点,初始值为数组的长度
- int bound = arr.length;
- while (flag){
- flag = false;
- for (int i = 1; i < bound ; i++) {
- if (arr[i-1] > arr[i]){
- swap(arr,i-1,i);
- flag = true;
- }
- }
- // 每次比较完,都减小一次边界
- bound--;
- }
- }
选择排序
步骤
选择排序的思路是:在没有排序的序列中,找到最小的或者最大的元素,放在已经排序的序列的尾部。
- 从第一个元素开始,找到之后的序列中比此元素小的值,交换之;
- 从第二个元素开始,找到之后的序列中比此元素小的值,交换之;
- 重复直到所有的元素都有序。
编码实现
- public static void selSort1(int[] arr){
- // 从第i个开始,依次为最小索引
- for (int i = 0; i < arr.length; i++) {
- int minIndex = i;
- // j为未排序元素的第一个数字
- for (int j = minIndex + 1; j < arr.length; j++) {
- // 如果最小索引位置上的数字比第j个数字大,那么就交换这个两个数字
- if(arr[minIndex]>arr[j]){
- swap(arr,j,minIndex);
- }
- }
- }
- }
插入排序
步骤
先指定一个有序的序列,对于没有排序的数据,依次跟有序序列中的数据进行比较,如果比较小,则插入到相应的位置中去。
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
编码实现
- public static void insertSort(int[] arr){
- // 表示已经排序的数组的下标,在这个下标之前的数据都已经进行了排序了
- int j;
- // i 代表循环次数,从1开始,因为默认第一个元素是已经排序的
- for (int i = 1; i < arr.length; i++) {
- // 临时变量,获取第i个元素的值
- int tmp = arr[i];
- // 在已经排序的前j个数据中,先从第i个开始,依次跟前一个值进行比较
- // 如果tmp的值比较小,将大元素也就是 arr[j-1] 往后移
- // 额,这里j是不能=0的,=0都TM溢出了 j-1 都小于0了!!
- for(j = i; j > 0 && tmp < arr[j - 1];j--){
- // 将大的元素往后移
- arr[j] = arr[j - 1];
- }
- // 如果没有比tmp小的了,或者j已经是0了,则在第j个位置插入该元素
- arr[j] = tmp;
- System.out.println(Arrays.toString(arr));
- }
- }
希尔排序
步骤
希尔排序可以说是插入排序的一个比较高效的实现方式。插入排序在对几户已经排序好的数据进行操作时,具有比较高的效率。因此希尔排序就是将一个数组中的元素分割成为几组,对每一组中的数据进行排序,然后再对整个数组进行排序。
编码实现
- public static void shellSort(int[] arr){
- int delta;
- // 定义分组的间隔,初始为数组长度的2的一半
- for(delta = arr.length/2; delta >= 1 ; delta/=2){
- // 以下就是插入排序的过程
- for (int i = delta; i < arr.length ; i++) {
- int j = i;
- int tmp = arr[i];
- // 这里与插入式排序不一样,是可以 = 0的,此时代表的是数组的第0个元素
- while (j - delta >= 0 && tmp < arr[j - delta]){
- arr[j] = arr[j - delta];
- j -= delta;
- }
- arr[j] = tmp;
- System.out.println(Arrays.toString(arr));
- }
- }
- }
堆排序
原理
堆排序是利用了最大堆、或者最小堆的性质进行排序的一种算法,这两种类型的堆分别具有以下的特点:父节点的值要大于(最小堆是小于)其左右子节点的值。由此,根节点的值为最大值(或者最小值)。交换根节点的值与数组末尾节点的值,再对剩余的元素进行重复的调整即可。
如果数组起始下标为0,那么节点i:
- 左节点为 2*i + 1
- 右节点为 2*i + 2
- 父节点为 (i-1) / 2
编码实现
- /**
- * 堆排序
- * @param arr
- */
- public static void heapSort(int[] arr){
- // 初始化最大堆
- // 当 i = n/2 时,n为奇数时,左节点为n,偶数时,左节点为n
- // 当 i> n/2时,左右节点的下标均 > n
- // 因此 n/2 是最后一个有子节点的节点了
- for (int i = arr.length / 2 ; i >= 0; i--){
- maxHeapify(arr,i,arr.length);
- //minHeapify(arr,i,arr.length);
- }
- for (int i = arr.length - 1; i > 0 ; i--) {
- // 交换根节点--最大或者最小节点,与最后一个节点的值
- swap(arr,0,i);
- // 对剩余的数据再次进行最大堆调整
- maxHeapify(arr,0,i);
- //minHeapify(arr,0,i);
- System.out.println(Arrays.toString(arr));
- }
- }
- /**
- * 最大堆化
- * @param arr 需要最大堆化的数组
- * @param parent
- * @param length
- */
- private static void maxHeapify(int[] arr,int parent,int length){
- int temp = arr[parent];
- // 从左节点开始
- int child = 2 * parent + 1;
- while (child < length){
- // 如果有孩子节点存在,且有孩子节点的值比左孩子节点的值要大,那么替换为右孩子节点
- if (child + 1 < length && arr[child] < arr[child + 1]){
- child ++;
- }
- // 如果父节点的值最大,那么就已经不需要调整了
- if (temp >= arr[child]){
- break;
- }
- // 将孩子节点的值赋予父节点
- arr[parent] = arr[child];
- // 从孩子节点的左孩子节点继续循环
- parent = child;
- child = 2*child + 1;
- }
- // 有两个作用
- // 1: 如果没有parent没有子节点,那么就把parent节点的值设置回来
- // 2: 如果parent有子节点,且符合交换的条件,那么现在这个parent就是之前的子节点,因为之前的子节点的值已经被替换到了父节点上,因此此操作是为了将父节点的值赋给之前的子节点
- arr[parent] = temp;
- }
归并排序
原理
现将一个数组进行拆分, 然后使得这个子数组有序,然后再合并数组。重复,直到这个数组有序。
编码实现
- /**
- * 归并排序算法的实现 -- 使用递归
- * @param arr 需要排序的数组
- * @param left 左边开始的节点
- * @param right 右边开始的节点
- * @param tmp 临时数组
- */
- private static void sort(int[] arr, int left, int right, int[] tmp) {
- if(left < right){
- // 定义中间节点
- int mid = (left + right) / 2;
- // 对左边子序列进行归并排序
- sort(arr,left,mid,tmp);
- // 对右边子序列进行归并排序
- sort(arr,mid + 1,right,tmp);
- // 合并左右两个子序列
- merge(arr,left,mid,right,tmp);
- }
- }
- /**
- * 对左右子序列进行合并操作
- * @param arr
- * @param left
- * @param mid
- * @param right
- * @param tmp
- */
- private static void merge(int[] arr, int left, int mid, int right, int[] tmp) {
- // 左子序列指针的初始化
- int i = left;
- // 右子序列指针的初始化
- int j = mid + 1;
- // 临时数组指针的初始化
- int t = 0;
- // 比较左右子序列的值,将较小的值依次放入tmp临时数组中
- while (i <= mid && j <= right){
- if(arr[i] <= arr[j]){
- tmp[t++] = arr[i++];
- }else {
- tmp[t++] = arr[j++];
- }
- }
- // 比较结束以后,会存在某一个子序列的值,还没有放进临时数组,因此需要将这些值放入临时数组
- // 将左子序列剩余元素放入数组
- while (i <= mid){
- tmp[t++] = arr[i++];
- }
- // 将右子序列剩余元素放入数组
- while (j <= right){
- tmp[t++] = arr[j++];
- }
- // 将临时数组的指针置为0
- t = 0;
- // 将临时数组中的数据复制到目标数组中
- while (left<=right){
- arr[left++] = tmp[t++];
- }
- System.out.println(Arrays.toString(arr));
- }
快速排序
原理
快速排序一样是使用了分治的思想,先选取一个枢纽值,将数组分成两个部分:在数组左边的数字都比枢纽值小,在数组右边的数字都比枢纽值大。重复,直到数组有序。
编码实现
- /**
- * 快速排序算法,本代码中使用数组中的最后一个元素作为pivot
- * @param arr
- */
- public static void quickSort(int[] arr){
- sort(arr,0,arr.length-1);
- }
- public static void sort(int[] arr, int left, int right){
- if (left < right){
- int pivot = partition(arr,left,right);
- sort(arr,left,pivot-1);
- sort(arr,pivot+1,right);
- }
- }
- /**
- * 此方法的目的有三个:
- * 1、 将比pivot值小的数字放在其前面
- * 2、 将比pivot值大的数字放在其后面
- * 3、 将pivot放在数组中正确的位置
- * 注意: 此处选择pivot的值为数组最后一个数字
- * @param arr
- * @param left
- * @param right
- * @return
- */
- private static int partition(int[] arr, int left, int right) {
- int pivot = arr[right];
- // 存放较小数字的索引
- int i = left - 1;
- for (int j = left; j <= right - 1 ; j++) {
- // 如果数字小于pivot,交换i j两个位置的值
- if(arr[j] <= pivot){
- i++;
- swap(arr,i,j);
- }
- }
- // 第i个数字存放的数字永远小于pivot,因此将i+1的值设置为pivot
- // 这样就可以保证pivot将数组分为了两个部分,前半部分都小于pivot,后半部分都大于pivot
- swap(arr,i+1,right);
- return i+1;
- }
常用排序算法的总结以及编码(Java实现)的更多相关文章
- Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法
Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排 ...
- Java 常用排序算法/程序员必须掌握的 8大排序算法
Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...
- 我们一起来排序——使用Java语言优雅地实现常用排序算法
破阵子·春景 燕子来时新社,梨花落后清明. 池上碧苔三四点,叶底黄鹂一两声.日长飞絮轻. 巧笑同桌伙伴,上学径里逢迎. 疑怪昨宵春梦好,元是今朝Offer拿.笑从双脸生. 排序算法--最基础的算法,互 ...
- Java常用排序算法及性能测试集合
测试报告: Array length: 20000 bubbleSort : 573 ms bubbleSortAdvanced : 596 ms bubbleSortAdvanced2 : 583 ...
- 常用排序算法的Java实现 - 1
学习编程语言时, 我们会接触到许多排序算法, 这里总结了一下常见的排序算法. 不定期更新. * 其实在Java中存在如Collections.sort()这样的方法来自动为我们排序, 不过学习排序算法 ...
- 面试中常用排序算法实现(Java)
当我们进行数据处理的时候,往往需要对数据进行查找操作,一个有序的数据集往往能够在高效的查找算法下快速得到结果.所以排序的效率就会显的十分重要,本篇我们将着重的介绍几个常见的排序算法,涉及如下内容: 排 ...
- 常用排序算法java实现
写在前面:纸上得来终觉浅.基本排序算法的思想,可能很多人都说的头头是到,但能说和能写出来,真的还是有很大区别的. 今天整理了一下各种常用排序算法,当然还不全,后面会继续补充.代码中可能有累赘或错误的地 ...
- 转载部长一篇大作:常用排序算法之JavaScript实现
转载部长一篇大作:常用排序算法之JavaScript实现 注:本文是转载实验室同门王部长的大作,找实习找工作在即,本文颇有用处!原文出处:http://www.cnblogs.com/ywang172 ...
- 常用排序算法的python实现和性能分析
常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...
随机推荐
- python进阶07 MySQL
python进阶07 MySQL 一.MySQL基本结构 1.认识MySQL #MySQL不是数据库,它是数据库管理软件 #MySQL如何组织数据 #如何进入MySQL数据库 #其他注意事项 #以表格 ...
- Luogu P1447 [NOI2010]能量采集 数论??欧拉
刚学的欧拉反演(在最后)就用上了,挺好$qwq$ 题意:求$\sum_{i=1}^{N}\sum_{j=1}^{M}(2*gcd(i,j)-1)$ 原式 $=2*\sum_{i=1}^{N}\sum_ ...
- python大战机器学习——聚类和EM算法
注:本文中涉及到的公式一律省略(公式不好敲出来),若想了解公式的具体实现,请参考原著. 1.基本概念 (1)聚类的思想: 将数据集划分为若干个不想交的子集(称为一个簇cluster),每个簇潜在地对应 ...
- NET Core 2.1.0 now available
ASP.NET Core 2.1.0 now available https://blogs.msdn.microsoft.com/webdev/2018/05/30/asp-net-core-2-1 ...
- SSRS-lookupSet-DataSet-分组查询
SSRS-lookupSet-DataSet-分组查询 来源:http://www.cnblogs.com/biwork/p/3621885.html 目录:http://www.cnblogs.co ...
- log4j.properties错误及配置详解
当在Eclipse上运行MapReduce程序遇到以上问题时,请检查项目中是否有log4j.properties配置文件,或者配置文件是否正确. 刚接触Hadoop的时候不太了解log4j.prope ...
- csrf攻击实例
CSRF 攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下执行在权限保护之下的操作.比如说,受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 ht ...
- left join \ right join \ inner join 详解
left join 和 left outer join 的区别 通俗的讲: A left join B 的连接的记录数与A表的记录数同 A right join B ...
- 利用wsdl.exe生成webservice代理类
通常要手动生成WebService代理类需要把一句生成语句,如 wsdl.exe /l:cs /out:D:\Proxy_UpdateService.cs http://localhost:1101 ...
- Unity3d发布apk文件并在Android虚拟机中运行的操作流程
总的流程分为以下6个步骤: 1.安装java_jdk 2.配置java环境变量 3.更新android的sdk 4.从Unity3d中发布出apk文件 5.创建android虚拟机并运行 6.将apk ...