java -- 排序算法
查找和排序算法是算法的入门知识,其经典思想可以用于很多算法当中。因为其实现代码较短,应用较常见。所以在面试中经常会问到排序算法及其相关的问题。但万变不离其宗,只要熟悉了思想,灵活运用也不是难事。一般在面试中最常考的是快速排序和归并排序,并且经常有面试官要求现场写出这两种排序的代码。对这两种排序的代码一定要信手拈来才行。还有插入排序、冒泡排序、堆排序、基数排序、桶排序等。
各种排序算法的比较:
插入排序
插入排序就像在分牌时可能要整理自己的牌,牌多的时候怎么整理呢?就是拿到一张牌,找到一个合适的位置插入。这个原理其实和插入排序是一样的。设计思想:每次插入之前,检查前面数据,如果小于当前数据,就往后移动一位,到无法移动时,就插入数据。
举个栗子:
对5,3,8,6,4这个无序序列进行简单插入排序,首先假设第一个数的位置时正确的,想一下在拿到第一张牌的时候,没必要整理。然后3要插到5前面,把5后移一位,变成3,5,8,6,4.想一下整理牌的时候应该也是这样吧。然后8不用动,6插在8前面,8后移一位,4插在5前面,从5开始都向后移一位。注意在插入一个数的时候要保证这个数前面的数已经有序。
代码如下:
public static void insertSort(int[] arr) { if(arr == null || arr.length == 0) return ; for(int i=1; i//假设第一个数位置时正确的;要往后移,必须要假设第一个。 int j = i; int target = arr[i]; //待插入的 //前面比target大的数都往后移 while(j > 0 & target < arr[j-1]) { arr[j] = arr[j-1]; j --; } //插入 arr[j] = target; } }
希尔排序
希尔排序是插入排序的一种高效率的实现,基本思想是:因为数据基本有序的情况下,插入排序是非常快的。根据步长进行两个数据的比较,如果小于就对调;走完一遍后,计算步长,在进行前面的比较;余此类推,当步长为1时,数据已经比较有序了,最后一次进行插入排序。
举个栗子:
初始数组: [26, 53, 67, 48, 57, 13, 48, 32, 60, 50 ]
结果数组: [13, 26, 32, 48, 48, 50, 53, 57, 60, 67]
代码如下:
public static void shellSort(int data[]) { if (data == null) return; int j = 0; int temp = 0; int len = data.length / 2; //计算步长 for (int increment = len; increment > 0; increment /= 2) { for (int i = increment; i < data.length; i++) { temp = data[i]; for (j = i; j >= increment; j -= increment) { if(temp < data[j - increment]){ data[j] = data[j - increment]; }else{ break; } } data[j] = temp; } } }
选择排序
选择排序的思想其实和冒泡排序有点类似,都是在一次排序后把最小的元素放到最前面。但是过程不同,冒泡排序是通过相邻的比较和交换。而选择排序是通过对整体的选择。
举个栗子:
对5,3,8,6,4这个无序序列进行简单选择排序,首先要选择5以外的最小数来和5交换,也就是选择3和5交换,一次排序后就变成了3,5,8,6,4,第二次就找出比5小的数找到4,找到4与5交换后变成3,4,8,6,5,对剩下的序列一次进行选择和交换,最终就会得到一个有序序列。
优点:
其实选择排序可以看成冒泡排序的优化,因为其目的相同,只是选择排序只有在确定了最小数的前提下才进行交换,大大减少了交换的次数。
代码如下:
public static void selectSort(int[] a) { if (a == null) return; int min = 0; int i = 0; int j = 0; int index = 0; int len = a.length; for (i = 0; i < len - 1; i++) { min = a[i]; index = i; for (j = i + 1; j < len; j++) { if (a[j] < min) { min = a[j]; index = j; } } a[index] = a[i]; a[i] = min; } }
堆排序
堆排序是借助堆来实现的选择排序,思想同简单的选择排序。
堆排序要解决的问题
如何由一个无序序列键成一个堆?
如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?
问题一
可以直接使用线性数组来表示一个堆,由初始的无序序列建成一个堆就需要自底向上从第一个非叶元素开始挨个调整成一个堆。
问题二
首先是将堆顶元素和最后一个元素交换。然后比较当前堆顶元素的左右孩子节点,因为除了当前的堆顶元素,左右孩子堆均满足条件,这时需要选择当前堆顶元素与左右孩子节点的较大者(大顶堆)交换,直至叶子节点。我们称这个自堆顶自叶子的调整成为筛选。
代码如下:
public static void heapSort(int[] array) { if (array == null) return; buildHeap(array);//构建堆 int n = array.length; int i = 0; for (i = n - 1; i >= 1; i--) { swap(array, 0, i); heapify(array, 0, i); } } //构建 public static void buildHeap(int[] array) { int n = array.length;//数组中元素的个数 for (int i = n / 2 - 1; i >= 0; i--) heapify(array, i, n); } public static void heapify(int[] A, int idx, int max) { int left = 2 * idx + 1;// 左孩子的下标(如果存在的话) int right = 2 * idx + 2;// 左孩子的下标(如果存在的话) int largest = 0;//寻找3个节点中最大值节点的下标 if (left < max && A[left] > A[idx]) largest = left; else largest = idx; if (right < max && A[right] > A[largest]) largest = right; if (largest != idx) { swap(A, largest, idx); heapify(A, largest, max); } } public static void swap(int[] array, int i, int j) { int temp = 0; temp = array[i]; array[i] = array[j]; array[j] = temp; }
冒泡排序
冒泡排序是最简单的排序之一了,其大体思想就是通过与相邻元素的比较和交换来把小的数交换到最前面。这个过程类似于水泡向上升一样,因此而得名。
举个栗子:
对5,3,8,6,4这个无序序列进行冒泡排序。首先从后向前冒泡,4和6比较,把4交换到前面,序列变成5,3,8,4,6。同理4和8交换,变成5,3,4,8,6,3和4无需交换。5和3交换,变成3,5,4,8,6,3.这样一次冒泡就完了,把最小的数3排到最前面了。对剩下的序列依次冒泡就会得到一个有序序列。
public static void bubbleSort(int[] arr) { if(arr == null || arr.length == 0) return ; for(int i=0; i) { for(int j=arr.length-1; j>i; j--) { if(arr[j]<arr[j-1]) { swap(arr, j-1, j); } } } } public static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
快速排序
快速排序是冒泡排序的改进版,由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用。特点是,挖坑填数 + 分治法。
基本思路
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
对挖坑填数进行总结:
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
代码如下:
//快速排序 ,l是0,r是数组的length void quickSort(int s[], int l, int r) { if (l < r) { //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 这是其他快速排序可能会用 // 初始化 int i = l, j = r, x = s[l]; while (i < j) { // 从右向左找第一个小于x的数,如果没找到,就一直往左查 while(i < j && s[j] >= x) j--; // 当找到,就把元素挖出来,填左边的坑,同时右边留一个坑 if(i < j) { s[i] = s[j]; // 左边指针向右移一位,后面就要用这个指针对应的数进行比较 i++; } // 从左向右找第一个大于等于x的数,如果没找到,就一直向右查 while(i < j && s[i] < x) i++; // 当找到,就把元素挖出来,填左边的坑,同时右边留一个坑 if(i < j) { s[j] = s[i]; // 右边指针向左移一位,后面就要用这个指针对应的数进行比较 j--; } } // 用初始值X填上最后剩下的坑 s[i] = x; quick_sort(s, l, i - 1); // 递归调用 quick_sort(s, i + 1, r); } }
归并排序
归并排序是另一种不同的排序方法,因为归并排序使用了递归分治的思想,所以理解起来比较容易。其基本思想是,先递归划分子问题,然后合并结果。把待排序列看成由两个有序的子序列,然后合并两个子序列,然后把子序列看成由两个有序序列。。。。。倒着来看,其实就是先两两合并,然后四四合并。。。最终形成有序序列。
代码如下:
// low是0,high是数组的length public static int[] mergeSort(int[] nums, int low, int high) { if (nums == null || low < 0 || low > nums.length-1 || high < 0) return nums; int mid = (low + high) / 2; if (low < high) { // 左边 mergeSort(nums, low, mid); // 右边 mergeSort(nums, mid + 1, high); // 左右归并 merge(nums, low, mid, high); } return nums; } public static void merge(int[] nums, int low, int mid, int high) { int[] temp = new int[high - low + 1]; int i = low;// 左指针 int j = mid + 1;// 右指针 int k = 0; // 把较小的数先移到新数组中 while (i <= mid && j <= high) { if (nums[i] < nums[j]) { temp[k++] = nums[i++]; } else { temp[k++] = nums[j++]; } } // 把左边剩余的数移入数组 while (i <= mid) { temp[k++] = nums[i++]; } // 把右边边剩余的数移入数组 while (j <= high) { temp[k++] = nums[j++]; } // 把新数组中的数覆盖nums数组 for (int k2 = 0; k2 < temp.length; k2++) { nums[k2 + low] = temp[k2]; } }
总结
- 在平均情况下,快速排序最快;
- 在最好情况下,插入排序和起泡排序最快;
- 在最坏情况下,堆排序和归并排序最快。
相关推荐
Java代码-排序-直接插入排序、希尔排序、直接选择排序、冒泡排序、堆排序、快速排序、归并排序中部分排序以及算法-贪心法,大家可以将源码下载下来进行学习,附带着注释和解释,有不理解的可以找博主一起探讨,共同...
此外,对于大字符串,效率也是一个需要考虑的因素,可以考虑使用更高效的排序算法或数据结构。 在提供的文件列表中,`Zifuchuan.java`可能是实现上述逻辑的源代码,而`www.pudn.com.txt`可能是一个包含测试数据的...
排序可以使用Java的`Collections.sort()`方法,如果你的数据存储在`List`或`ArrayList`中,或者自定义排序算法,如果数据存储在其他数据结构中。 3. **`TableModel`更新**:完成排序后,必须更新`TableModel`以反映...
`Java-master_排序_`这个项目很显然是一个专注于Java排序算法实现的代码库。在这个项目中,开发者可能封装了一系列的排序工具类或者方法,方便其他开发人员在处理数组、集合等数据结构时进行排序操作。 首先,我们...
该资源提供了Java中实现堆排序的全面指南。文档中涵盖了堆排序的基本概念,包括如何对数组进行排序以及如何在Java中实现堆排序。...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
该资源提供了Java中实现插入排序的全面指南。文档中涵盖了插入排序的基本概念,包括如何对数组进行排序以及如何在Java中实现插入排序。...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
Java哈希算法排序算法数据结构知识点总结 以下是关于Java哈希算法排序算法数据结构的知识点总结: 1. 哈希算法的速度问题:在讨论哈希算法的速度问题时,需要考虑到哈希函数的选择和实现方式。在大多数情况下,...
Java排序算法是编程领域中的重要知识点,特别是在处理数据集合时,高效的排序算法能显著提升程序的性能。这里我们将深入探讨几种常见的Java排序算法,包括冒泡排序、堆排序、插入排序、合并排序、快速排序以及选择...
在编程领域,排序算法是计算机科学中的核心概念,特别是在Java这样的高级编程语言中。排序算法是用来组织和优化数据结构的关键工具,它可以帮助我们快速查找、分析和处理大量数据。本篇将深入探讨Java中实现的几种...
该资源提供了Java中实现冒泡排序的全面指南。文档中涵盖了冒泡排序的基本概念,包括如何对数组进行排序以及如何在Java中实现冒泡排序。...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
该资源提供了一份全面的指南,介绍了如何在Java中实现归并排序。文档中涵盖了归并排序的基本概念,包括如何对数组进行排序以及如何在Java中...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
该资源提供了一份全面的指南,介绍了如何在Java中实现希尔排序。文档中涵盖了希尔排序的基本概念,包括如何对数组进行排序以及如何在Java中...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
Java-快速排序、冒泡排序和堆排序三种排序讲解、对比及总结 Java-快速排序、冒泡排序和堆排序三种排序讲解、对比及总结 Java-快速排序、冒泡排序和堆排序三种排序讲解、对比及总结
该资源提供了Java中如何实现选择排序的全面指南。文档中涵盖了选择排序的基本概念,包括如何对数组进行排序以及如何在Java中实现选择排序。...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
这份资源提供了Java中如何实现快速排序的全面指南。文档中涵盖了快速排序的基本概念,包括如何对数组进行排序以及如何在Java中实现快速排序。...我们相信,该资源将成为想提高算法设计技能的Java程序员的宝贵参考资料。
本文将详细探讨标题所提及的几种排序算法:合并排序、插入排序、希尔排序、快速排序、冒泡排序以及桶排序,并结合Java语言的实现进行解析。 1. **合并排序(Merge Sort)**: 合并排序是一种基于分治策略的排序算法...
在编程领域,尤其是Java开发中,数据结构与算法是核心基础,它们对于编写高效、优化的代码至关重要。数据结构是组织、存储和处理数据的方式,而算法是解决问题或执行特定任务的步骤序列。理解并掌握这两者对于成为一...
Java排序算法 - 插入排序 插入排序(Insertion Sort)是一种简单的排序算法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增 1 的有序表。该算法的实现非常简单,但其时间复杂度...
**插入排序**是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。这种算法对大数据量的处理效率较低,但对于小规模数据或者部分有序的...