本文主要是介绍排序方法总结——Java语言描述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
排序总结——Java语言描述
各种排序方法Java源代码链接:各种排序方法Java源代码链接
一 排序概述
1.1 排序的定义
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。
1.2 排序的分类
排序分为内部排序
和外部排序
内部排序
:若整个排序过程不需要访问外存便能完成(如软盘、硬盘),则称此类排序问题为内部排序
;
外部排序
:若参加排序的记录数量很大,整个序列的排序过程**不可能在内存中
完成**,则称此类排序问题为外部排序
。
二 内部排序
2.1 内部排序概述
内部排序的过程是一个逐步扩大记录的有序序列长度的过程。基于不同的“扩大” 有序序列长度的方法,内部排序方法大致可分下列几种类型:
1**插入类**:将无序子序列中的一个或几个记录插入
到有序序列中,从而增加记录的有序子序列的长度。
1)直接插入排序(基于顺序查找)
2) 折半插入排序(基于折半查找)
3) 希尔插入排序(基于逐趟缩小增量)
2 交换类:通过“交换”无序序列中的记录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度
1) 冒泡排序
2) 快速排序
3 选择类:从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。
1) 简单选择排序
2) 树形选择排序
3) 堆排序
4**归并类**:通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度。
1) 归并排序
5 其他类
2.2 各种排序方法详解
插入类排序
2.2.1 直接插入排序法
a) 思想:利用 “顺序查找”实现“在R[1..i-1]中查找R[i]的插入位置”
b) Java语言描述的关键代码
package insertCategorySort;import java.util.ArrayList;
import java.util.Scanner;/**
* @Description 直接插入排序(基于顺序查找)
* @author zhiman in 2017年10月7日 下午5:26:45 mail-zhimanma@gmail.com
* @version V1.0
*
*/
public class SimpleInsertionSort {public static void main(String[] args) {ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("请输入待排数据:");for(int i = 0; i < num; i++){int temp = scanner.nextInt();arrs.add(temp);}scanner.close();Integer[] arr = new Integer[num];arrs.toArray(arr);//泛型方法调用System.out.println("排序完成后的数据:");SimpleInsertionSort.<Integer>insertionSort(arr);for(Integer in:arr) {System.out.println(in);}}/** * TODO(方法功能描述) 直接插入排序核心代码.* @author zhiman in 2017年10月7日 下午5:28:56 */public static <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType[] data) {//暂存带排序的元素int i;for(int pointer = 1; pointer < data.length; pointer++) {AnyType temp = data[pointer];for (i = pointer; i > 0 && temp.compareTo(data[i - 1]) < 0; i--) {//if (temp.compareTo(data[i-1]) < 0) data[i] = data[i - 1];}data[i] = temp;}}
}
c) 算法分析
直接插入排序法 是稳定的排序排序算法
,时间复杂度为 O(n2)
2.2.2 折半插入排序法
a) 思想:利用 “折半查找”实现“在R[1..i-1]中查找R[i]的插入位置”
b) Java语言描述的关键代码
package insertCategorySort;import java.util.ArrayList;
import java.util.Scanner;/**
* @Description TODO 折半插入排序法
* @author zhiman in 2017年10月7日 下午9:49:48 mail:zhimanma@gmail.com
* @version V1.0
*
*/
public class BinaryInsertionSort {public static void main(String[] args) {ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("折半插入排序——请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("折半插入排序——请输入待排数据:");for(int i = 0; i < num; i++){int temp = scanner.nextInt();arrs.add(temp);}scanner.close();Integer[] arr = new Integer[num];arrs.toArray(arr);//泛型方法调用System.out.println("折半插入排序——排序完成后的数据:");new BinaryInsertionSort().<Integer>binaryInsert(arr);for(Integer in:arr) {System.out.println(in);}} public <AnyType extends Comparable<? super AnyType>> void binaryInsert(AnyType[] data) {int low,high,mid;for (int pointer = 1; pointer < data.length; pointer++) {AnyType temp = data[pointer];low = 0;high = pointer - 1;//查找元素插入位置while (low <= high) {mid = (low + high) / 2;if (temp.compareTo(data[mid]) < 0) {high = mid - 1;} else {low = mid + 1;}}//移动元素for (int j = pointer; j > high + 1; j--) {data[j] = data[j - 1];}//将待排元素放到合适位置,即high+1的位置data[high + 1] = temp;}}
}
c) 算法分析
折半插入排序法 是稳定的排序排序算法
,时间复杂度为 O(n2)
2.2.3 希尔排序法
a) 算法思想:先将整个待排记录序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行一次直接插入排序。
b)算法描述
1、选择一个步长序列 t1,t2,…,tk,其中ti>ti+1,tk=1 ;
2、 按步长序列个数k,对序列进行k趟排序;
3、每趟排序,根据对应的步长 ti ,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅步长因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。
c)关键代码
package insertCategorySort;import java.util.ArrayList;
import java.util.Scanner;public class ShellInsertionSort {public static void main(String[] args) {//ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("希尔插入排序——请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("希尔插入排序——请输入待排数据:");Integer[] arr = new Integer[num];for(int i = 0; i < num; i++){int temp = scanner.nextInt();arr[i] = temp;}scanner.close();//arrs.toArray(arr);//泛型方法调用System.out.println("希尔插入排序——排序完成后的数据:");new ShellInsertionSort().<Integer>shellInsert(arr);for(Integer in:arr) {System.out.println(in);}}/** * TODO(方法功能描述) 希尔排序关键代码* @param data 待排数据* @author zhiman in 2017年10月8日 上午11:15:54 */public <AnyType extends Comparable<? super AnyType>> void shellInsert( AnyType[] data ) {//初始增量选择data.length/2,后面增量依次选择上次增量的0.5倍//这种增量叫做希尔增量for ( int gap = data.length/2; gap > 0; gap /= 2 ) {for ( int i = gap; i < data.length; i++ ) {AnyType temp = data[i];int j;for ( j = i;j >= gap/*&& temp.compareTo( data[ j - gap ] ) < 0*/; j -= gap ) {if ( temp.compareTo( data[ j - gap ] ) < 0 ) {data[ j ] = data[ j - gap ];} else break;}data[ j ] = temp;}}}
}
d) 算法分析
1.希尔排序方法是一个不稳定的排序方法
2.关键字的比较次数与记录移动次数依赖于步长因子序列的选取
3.使用希尔增量时,希尔排序最差时间复杂度为$O(n^2)$
交换类排序
2.2.4 冒泡排序法
a) 思想:它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
b) Java语言描述的关键代码
package exchangeCategorySort;import java.util.Scanner;public class BubbleSort {public static void main(String[] args) {//ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("冒泡排序——请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("冒泡排序——请输入待排数据:");Integer[] arr = new Integer[num];for(int i = 0; i < num; i++){int temp = scanner.nextInt();arr[i] = temp;}scanner.close();//arrs.toArray(arr);//泛型方法调用System.out.println("冒泡排序——排序完成后的数据:");new BubbleSort().<Integer>bubbleSortMethod(arr);for(Integer in:arr) {System.out.println(in);}}/** * TODO(方法功能描述) 冒泡排序核心代码* @param data 待排数据* @author zhiman in 2017年10月8日 下午10:14:11 */public <AnyType extends Comparable<? super AnyType>>void bubbleSortMethod(AnyType[] data) {//改进算法,设置标志位boolean flag = true;for (int i = 0; i < data.length - 1 && flag ; i++) {flag = false;for (int j = 0; j < data.length - i - 1; j++) {if (data[j].compareTo(data[j+1]) > 0) {AnyType temp = data[j+1];data[j+1] = data[j];data[j] = temp;//如果某次循环,没有交换,则排序完成flag = true;}}}}
}
b) 算法分析
1. 上述改进后的冒泡排序算法,当待排数据顺序有序时,有最好的时间复杂 O(n) ,当待排数据逆序有序时,有最差的时间复杂度 O(n2)
2. 冒泡排序是稳定的排序算法
2.2.4 快速排序法
a) 思想:快速排序(quick sort)是对起泡排序的一种改进。通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,然后分别对这两部分记录继续进行排序,直到整个序列有序。
b) Java语言描述的关键代码
javapackage exchangeCategorySort;import java.util.*;public class QuickSort {public static void main(String[] args) {List<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("快速排序——请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("快速排序——请输入待排数据:");Integer[] arr = new Integer[num];for(int i = 0; i < num; i++){int temp = scanner.nextInt();arr[i] = temp;arrs.add(temp);}scanner.close();//arrs.toArray(arr);//泛型方法调用System.out.println("快速排序——排序完成后的数据:");QuickSort qs = new QuickSort();//调用快排算法一qs.<Integer>quickSortOne(arr,0,arr.length - 1);for(Integer in:arr) {System.out.println(in);}//调用快排算法二qs.quickSortTWo(arrs);for(Integer in:arrs) {System.out.println(in);}}/** * TODO(方法功能描述) 第一种快速排序方法* @param data 待排数据* @param low 待排数据低下标* @param high 待排数据高下标* @author zhiman in 2017年10月9日 下午4:17:23 */public <AnyType extends Comparable<? super AnyType>>void quickSortOne(AnyType[] data , int low , int high) {int keyElementPosition;//此处必须是if判断,否则无限循环if (low < high) {keyElementPosition = doPartition(data,low,high);//对一次划分的左边元素快速排序quickSortOne(data,low,keyElementPosition - 1);//对一次划分的右边元素快速排序quickSortOne(data,keyElementPosition + 1,high);}}/** * TODO(方法功能描述) 一次划分* @param data 待排数据* @param low 待排数据低下标* @param high 待排数据高下标* @return 枢纽元素插入位置* @author zhiman in 2017年10月9日 下午3:43:00 */private <AnyType extends Comparable<? super AnyType>> int doPartition(AnyType[] data , int low , int high) {//获取low high 和(low + high)/2中间元素,并将其置于low所指位置getMidian(data,low,high);AnyType key = data[low];//选取数组下标为low元素作为枢纽//直到low = high 时循环结束while (low < high) {//循环直到找到一个比枢轴元素小的元素while ( low < high && key.compareTo( data[high] ) < 0 ) {high--;}data[low] = data[high];//循环直到找到一个比枢轴元素大的元素while ( low < high && key.compareTo( data[low] ) > 0 ) {low++;}data[high] = data[low];}data[low] = key;return low;} /** * TODO(方法功能描述) 一种简单实现快排的方法* @param items List集合* @author zhiman in 2017年10月9日 下午8:19:43 */public void quickSortTWo(List<Integer> items) {if (items.size() > 1) {List<Integer> smaller = new ArrayList<Integer>();List<Integer> same = new ArrayList<Integer>();List<Integer> larger = new ArrayList<Integer>();//得到枢轴元素Integer keyItem = items.get(items.size() / 2);for (Integer it:items) {if (it < keyItem) {smaller.add(it);} else if (it > keyItem) {larger.add(it);} else {same.add(it);}}quickSortTWo(smaller);quickSortTWo(larger);items.clear();items.addAll(smaller);items.addAll(same);items.addAll(larger);}}/** * TODO(方法功能描述) 获取中值,并将其放到left所指位置* @param a 待排数据* @param left 待排数据低索引* @param right 待排数据高索引* @return 枢轴元素* @author zhiman in 2017年10月10日 下午3:40:51 */private <AnyType extends Comparable<? super AnyType>> void getMidian(AnyType[] a, int left, int right){int mid = (left + right) / 2;if (a[mid].compareTo(a[left]) < 0)swap(a,left,mid);if (a[right].compareTo(a[left]) < 0)swap(a,left,right);if (a[right].compareTo(a[mid]) < 0)swap(a,mid,right);//让中间值位于下标为right - 1的位置swap(a , mid, left);}private <AnyType extends Comparable<? super AnyType>> void swap(AnyType[] a, int left, int right) {AnyType temp = a[left];a[left] = a[right];a[right] = temp;}}
c) 算法分析
1. 快速排序是不稳定的排序方法
2. 快速排序平均时间复杂度为 O(nlogn) —牺牲稳定性换来效率提升
3. 当待排序列逆序有序时,快速排序退化为冒泡排序,有最差时间复杂度 O(n2)
选择类排序
2.2.5 简单选择排序法
a) 思想:
第 1 趟选择: 从 1—n 个记录中选择关键字最小的记录,并和第 1 个记录交换。
第 2 趟选择:从 2—n 个记录中选择关键字最小的记录,并和第 2 个记录交换。
*
*
*
第 n 趟选择:从 (n-1)—n 个记录中选择关键字最小的记录,并和第 n-1 个记录交换。
b) Java语言描述的关键代码
package insertCategorySort;import java.util.ArrayList;
import java.util.Scanner;/**
* @Description 直接插入排序(基于顺序查找)
* @author zhiman in 2017年10月7日 下午5:26:45 mail-zhimanma@gmail.com
* @version V1.0
*
*/
public class SimpleInsertionSort {public static void main(String[] args) {ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("请输入待排数据:");for(int i = 0; i < num; i++){int temp = scanner.nextInt();arrs.add(temp);}scanner.close();Integer[] arr = new Integer[num];arrs.toArray(arr);//泛型方法调用System.out.println("排序完成后的数据:");new SimpleInsertionSort().<Integer>insertionSort(arr);for(Integer in:arr) {System.out.println(in);}}/** * TODO(方法功能描述) 直接插入排序核心代码.* @author zhiman in 2017年10月7日 下午5:28:56 */public <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType[] data) {//暂存带排序的元素int i;for(int pointer = 1; pointer < data.length; pointer++) {AnyType temp = data[pointer];for (i = pointer; i > 0 /*&& temp.compareTo(data[i - 1]) < 0*/; i--) {if (temp.compareTo(data[i-1]) < 0) data[i] = data[i - 1];else break;}data[i] = temp;}}
}
c) 算法分析: 时间复杂度: O(n2) ,且是不稳定的排序法。
2.2.6 堆排序
a) 思想:在大顶堆中,将堆顶和最后一个记录交换,即得第一趟的结果;再使剩余n-1个元素的序列重又建成一个堆,则得到n个元素的次大值。如此反复执行,便能得到一个有序序列,这个过程称为堆排序。
b) Java语言描述的关键代码
package selectCategorySort;import java.util.Scanner;/**
* @Description 对用数组存储的堆进行排序
* @author zhiman in 2017年10月10日 下午9:42:08 mail-zhimanma@gmail.com
* @version V1.0
*
*/
public class HeapSort {public static void main(String[] args) {//ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("堆排序——请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("堆排序——请输入待排数据:");Integer[] arr = new Integer[num];for(int i = 0; i < num; i++){int temp = scanner.nextInt();arr[i] = temp;}scanner.close();//arrs.toArray(arr);//泛型方法调用System.out.println("堆排序——排序完成后的数据:");new HeapSort().<Integer>heapSort(arr);for(Integer in:arr) {System.out.println(in);}}/** * TODO(方法功能描述) 堆排序关键代码* @param data 待排数据* @author zhiman in 2017年10月10日 下午9:25:07 */public <AnyType extends Comparable<? super AnyType>>void heapSort(AnyType[] data) {//建堆,对于有n个元素的堆,从n/2处开始调整堆,数组从0下标开始,所以此处需再减一for (int i = data.length / 2 - 1; i >= 0; i--) {percDown(data,i,data.length);}//删除堆顶最大元素for (int i = data.length - 1; i > 0; i--) {//swap(data,0,i)中i代表元素下标swap(data,0,i);//percDown(data,0,i)中i代表堆中元素个数percDown(data,0,i); }}/** * TODO(方法功能描述) 删除堆顶元素并重建堆* @param a 待排数据* @param i * @param n 堆元素个数* @author zhiman in 2017年10月10日 下午9:31:13 */public <AnyType extends Comparable<? super AnyType>>void percDown(AnyType[] a,int i, int n) {int child;AnyType temp;for (temp = a[i]; getLeftChild(i) < n; i = child) {child = getLeftChild(i);//n-1为数组表示的堆得最后一个元素的下标,让child指向左右孩子中较大的元素下标if ( child != n-1 && a[child].compareTo( a[child + 1] ) < 0 ) {child++;}//将结点的值与该节点左右孩子中较大的值比较,并调整堆if( temp.compareTo( a[child] ) < 0) {a[i] = a[child];} elsebreak;}a[i] = temp;}/** * TODO(方法功能描述) 得到元素i左孩子下标* @param i* @return 元素i左孩子下标* @author zhiman in 2017年10月10日 下午9:27:24 */private int getLeftChild (int i) {//用数组来存储堆,堆顶元素下标为0,所以左孩子下标为2*i+1;return 2 * i + 1;}/** * TODO(方法功能描述) 交换数组元素* @param a* @param left* @param right* @author zhiman in 2017年10月10日 下午9:48:59 */private <AnyType extends Comparable<? super AnyType>> void swap(AnyType[] a, int left, int right) {AnyType temp = a[left];a[left] = a[right];a[right] = temp;
}
}
c) 算法分析
1. 堆排序最坏情况下,时间复杂度也为 O(nlogn2) 。
2. 堆排序是不稳定的排序算法。
3. 堆排序相对简单选择排序而言牺牲了空间换取效率的提升。
归并类排序
2.2.7 归并排序法
a) 思想: 将两个或两个以上的有序子序列 “归并” 为一个有序序列。
b) Java语言描述的关键代码
package mergeCategorySort;import java.util.Scanner;public class MergeSort {public static void main(String[] args) {//ArrayList<Integer> arrs = new ArrayList<Integer>();Scanner scanner = new Scanner(System.in);System.out.println("归并排序——请输入待排序数的个数:");int num = scanner.nextInt();System.out.println("归并排序——请输入待排数据:");Integer[] arr = new Integer[num];for(int i = 0; i < num; i++){int temp = scanner.nextInt();arr[i] = temp;}scanner.close();//arrs.toArray(arr);//泛型方法调用System.out.println("归并排序——排序完成后的数据:");new MergeSort().<Integer>mergeSort(arr);for(Integer in:arr) {System.out.println(in);}}/** * TODO(方法功能描述) 重载方法 * @param a 待排数据* @author zhiman in 2017年10月10日 下午11:18:18 */public <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType[] a) {@SuppressWarnings("unchecked")AnyType[] tempArray = (AnyType[])new Comparable[a.length];mergeSort(a, tempArray, 0, a.length - 1);}/** * TODO(方法功能描述) 归并排序关键代码* @param a 待排数据* @param tempArray 暂存数组* @param left 下标* @param right 下标* @author zhiman in 2017年10月10日 下午11:11:45 */public <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType[] a, AnyType[] tempArray, int left, int right) {if (left < right) {int center = (left + right) / 2;mergeSort(a, tempArray, left, center);mergeSort(a, tempArray, center + 1, right);merge(a, tempArray, left, center + 1, right);}}/** * TODO(方法功能描述) 归并元素* @param a 待排数据* @param tempArray 暂存数组* @param leftPos 左表起始位置* @param rightPos 右表起始位置* @param rightEnd 右表终止位置* @author zhiman in 2017年10月10日 下午11:23:01 */private <AnyType extends Comparable<? super AnyType>> void merge(AnyType[] a, AnyType[] tempArray, int leftPos, int rightPos, int rightEnd) {//左表终止位置int leftEnd = rightPos - 1;int tempPos = leftPos;//元素总个数int numElements = rightEnd - leftPos + 1;//循环归并直到两个表中一个表元素全部归并到新表while (leftPos <= leftEnd && rightPos <= rightEnd) {if ( a[leftPos].compareTo( a[rightPos] ) <= 0 ) {tempArray[tempPos++] = a[leftPos++];} else {tempArray[tempPos++] = a[rightPos++];}}//若右表归并完,则复制左表剩余元素到tempArraywhile ( leftPos <= leftEnd ) {tempArray[tempPos++] = a[leftPos++];}//若左表归并完,则复制右表剩余元素到tempArraywhile ( rightPos <= rightEnd ) {tempArray[tempPos++] = a[rightPos++];}//将tempArray复制到afor (int i = 0; i < numElements; i++ , rightEnd--) {//whya[rightEnd] = tempArray[rightEnd];}}
}
c) 算法分析
1. 第i趟归并后,有序子文件长度为2i,因此对有n个记录的文件排序,必须做 logn2 向上取整趟归并,每趟归并所花的时间是O(n) ;所以,二路归并排序的时间复杂性为 O(nlogn2) 。
2. 归并排序是稳定的。
各种排序方法Java源代码链接:各种排序方法Java源代码链接
这篇关于排序方法总结——Java语言描述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!