Java中的排序
冒泡排序
原理:从一个数开始,依次往后比较,如果前面的数字比后面的大就交换,否则不交换,类似烧开水,水壶底的水泡往上冒。
图解分析:
现以数组[24,69,80,57,13]为例
代码实现
public class MyTest2 {
public static void main(String[] args) {
int[] arr={24,69,80,57,13};
for (int j = 0; j < arr.length - 1; j++) {
for (int i = 0; i < arr.length - 1 - j; i++) {
if (arr[i]>arr[i+1]){
int t=arr[i];
arr[i]=arr[i+1];
arr[i+1]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
选择排序
原理:每一趟从待排序的数据元素选择最小的,存放到排序序列的起始位置,然后,再从剩余未排元素中继续寻找最小的,然后放到已排序的末尾,以此类推,直到所有元素均排完为止。
图解分析:
代码实现:
public class MyTest2 {
public static void main(String[] args) {
int[] arr={24,69,80,57,13};
for (int j = 0; j < arr.length - 1; j++) {
for (int i=1+j;i<arr.length;i++){
if (arr[j]>arr[i]){
int t=arr[i];
arr[i]=arr[j];
arr[j]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
直接插入排序
原理:有一个待排序的数组array,数组长度为n。假设有有一个已经排好序的有序数组,用该数组对未排序的数组的元素,每一个元素都去与已经拍好的数组中的元素比较,然后有序的插入到有序的数组当中,直到将所有的待排序的记录全部插入为止。
例如:
•49,38,65,97,76,13,27 原始数据
•[49],38,65,97,76,13,27 从1索引开始插入
•[38,49], ,65,97,76,13,27
•[38,49,65] 97,76,13,27
•[38,49,65,97] 76,13,27
•[38,49,65,76,97]13,27
•[13,27,38,49,65,76,97],27
•[13,27,38,49,65,76,97]
代码实现
public class MyTest2 {
public static void main(String[] args) {
int[] arr={49,38,65,97,76,13,27 };
for (int i = 1; i < arr.length; i++) {
for (int j=i;j>0;j--){
if (arr[j]<arr[j-1]){
int t=arr[j];
arr[j]=arr[j-1];
arr[j-1]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
希尔排序
原理:它是对直接插入排序的一种改进,对于一个待排序的数列,取一个小于数列长度的间隔数,所有这个间隔数上的元素分成一组,然后对各组内的元素进行直接插入排序,这一趟排序之后,每一组的元素都是有序的,然后减小间隔数,继续去比较,当间隔数为1时,整个数列是有序的。
图解分析:
增量的选择一般选数组长度的一半,但是这样不是最合理的,我们用Kunth序列进行希尔排序,a=3*d+1;
代码实现
public class MyTest2 {
public static void main(String[] args) {
int[] arr={46,55,13,42,17,94,05,70};
int jiange=1;
while (jiange<arr.length/3) {
jiange = 3 * jiange + 1;//数组的最大间隔
}
for (int h = jiange; h>0;h=(h-1)/3 ) {
for (int j = h; j < arr.length;j++) {
for (int i=j;i>h-1;i=i-h){
if (arr[i]<arr[i-h]){
int t=arr[i];
arr[i]=arr[i-h];
arr[i-h]=t;
}
}
}
}
System.out.println(Arrays.toString(arr));
}
}
输出结果:[5, 13, 17, 42, 46, 55, 70, 94]
归并排序
原理:归并排序是一种递归算法,不断将列表拆分为一半,如果列表为空或有一个项,则按定义进行排序。如果列表有多个项,我们分割列表,并递归调用两个半部分的合并排序。一旦对两半排序完成,获取两个较小的排序列表并将它们组合成单个排序的新列表的过程。
图解分析:
代码实现
public class MyTest2 {
public static void main(String[] args) {
int[] arr = {56, 93, 17, 77, 31, 44, 55, 20};
chaifen(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
private static void chaifen(int[] arr, int startindex, int endindex) {
int centerindex=(startindex+endindex)/2;
// System.out.println(startindex);
// System.out.println(endindex);
if(startindex<endindex){
chaifen(arr,startindex,centerindex);
chaifen(arr,centerindex+1,endindex);
mergeSort(arr,startindex,centerindex,endindex);
}
}
private static void mergeSort(int[] arr, int startindex, int centerindex, int endindex) {
int[] temoArray=new int[endindex-startindex+1];
int index=0;
int i=startindex;
int j=centerindex+1;
while (i<=centerindex&&j<=endindex){
if (arr[i]<=arr[j]){
temoArray[index]=arr[i];
i++;
}else {
temoArray[index]=arr[j];
j++;
}
index++;
}
while (i<=centerindex){
temoArray[index]=arr[i];
i++;
index++;
}
while (j<=endindex){
temoArray[index]=arr[j];
j++;
index++;
}
// System.out.println(Arrays.toString(temoArray));
// System.out.println(startindex);
for (int k = 0; k < temoArray.length; k++) {
arr[k+startindex]=temoArray[k];
}
}
}
快速排序
选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。
一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。
代码实现:
public class MyTest2 {
public static void main(String[] args) {
int[] arr = {56, 93, 17, 77, 31, 44, 55, 20};
QuickSort1(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
private static void QuickSort1(int[] arr, int startindex, int endindex) {
if (startindex < endindex) {
int index = getIndex(arr, startindex, endindex);
QuickSort1(arr, startindex, index - 1);
QuickSort1(arr, index + 1, endindex);
}
}
private static int getIndex(int[] arr, int startindex, int endindex) {
int i = startindex;
int j = endindex;
int x = arr[i];
while (i < j) {
while (i < j && arr[j] >= x) {
j--;
}
if (i < j) {
arr[i] = arr[j];
i++;
}
while (i < j && arr[i] <= x) {
i++;
}
if (i < j) {
arr[j] = arr[i];
j--;
}
}
arr[i]=x;
return i;
}
}
基数排序
原理:类似于桶式排序,我们需要给待排序记录准备10个桶,为什么是10个??因为一个数的任何一位上,其数字大小都位于0~9之间,因此采用10个桶,桶的编号分别为0,1,2,3,4…9,对应待排序记录中每个数相应位的数值,基数排序也是因此而得名。我们先根据待排序记录的每个数的个位来决定让其加入哪个桶中
如:待排序数组为
278 109 63 930 589 184 505 269 8 83
求取每个数的个位数,依次为:8 9 3 0 9 4 5 9 8 3
依照其个位数决定将其加入哪个桶中
[0] | 930 | |||
[1] | ||||
[2] | ||||
[3] | 63 | 83 | ||
[4] | 184 | |||
[5] | 505 | |||
[6] | ||||
[7] | ||||
[8] | 278 | 8 | ||
[9] | 109 | 589 | 269 |
此步骤即为教材中所说的分配,接下来就是要进行收集,依照桶的编号,将含有数据的桶中的数据依次取出,形成的新的数据记录为:
930 63 83 184 505 278 8 109 589 269
再对这个数组按照十分位进行分配进桶,收集,最后再按照百位进行分配进桶,收集。就可得到最终的排序结果。
public class MyTest2 {
public static void main(String[] args) {
int[] arr = {278,109,63,930,589,184,505,269,8,83};
sortArrays(arr);
System.out.println(Arrays.toString(arr));
}
private static void sortArrays(int[] arr) {
int[][] temparry = new int[10][arr.length];
int max = getMax(arr);
int[] counts = new int[arr.length];
int len = String.valueOf(max).length();
for (int i = 0, n = 1; i < len; i++, n *= 10) {
for (int j = 0; j < arr.length; j++) {
int i1 = arr[j] / n % 10;
temparry[i1][counts[i1]++] = arr[j];
}
int index=0;
for (int k = 0; k < counts.length; k++) {
if (counts[k] != 0) {
for (int l = 0; l < counts[k]; l++) {
arr[index]=temparry[k][l];
index++;
}
counts[k]=0;
}
}
}
}
private static int getMax ( int[] arr){
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
}