介绍
- 选择排序
- 冒泡排序
- 插入排序
- 基数排序
- 快速排序
- 归并排序
各种排序算法已封装好,注释详细,可直接复制使用。
代码
import java.util.Arrays;
/**
* 测试排序算法
* 因为排序算法经常使用,所以将其设置为静态的
* 排序结果都是升序
* 1. 选择排序
* 2. 冒泡排序
* 3. 插入排序
* 4. 基数排序
* 5. 快速排序
* 6. 归并排序
* @author dxt
*
*/
public class Sort {
public static void main(String[] args){
int[] arr = {4, 3, 2, 1, 100, 30, 0, 22};
System.out.println("待排序的数组为:" + Arrays.toString(arr));
//selectSort(arr); //选择排序
//bubbleSort(arr); //冒泡排序
//insertSort(arr); //插入排序
//radixSort(arr); //基数排序
//quickSort(arr, 0, arr.length-1); //快速排序
mergeSort(arr); //归并排序
System.out.println("排序后的数组为:" + Arrays.toString(arr));
}
/**
* java中无实现swap()函数
* @param arr
* @param index1
* @param index2
*/
public static void swap(int[] arr, int index1, int index2){
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
/**
* 选择排序
* 内循环每次在无序数组中选择一个最大的
* 外循环将内循环中选出的最大的数据放到无序数据的最后一个位置
* @param array
*/
public static void selectSort(int[] array){
for(int i=0; i<array.length-1; i++){
int max_num_index = 0;
for(int j=0; j<array.length-i; j++){
if(array[max_num_index] < array[j]){
max_num_index = j;
}
}
swap(array, max_num_index, array.length-1-i);
}
}
/**
* 及时终止的冒泡排序
* 内层循环通过依次比较相邻的两个数据,在无序数据中找出最大的那个数,然后将最大的那个数放到
* 无序区域的最后位置
* @param arr
*/
public static void bubbleSort(int[] arr){
for(int i=0; i<arr.length-1; i++){
boolean flag = true;
for(int j=0; j<arr.length-1-i; j++){
if(arr[j] > arr[j+1]){
swap(arr, j, j+1);
flag = false;
}
}
if(flag){
break;
}
}
}
/**
* 插入排序
* 1. 将待排序数组分为两部分,前一部分(索引靠前)是有序的,后一部分(索引在后)是无序的
* 2. 初始时,将数组中的第1个元素作为有序部分, 其它数据作为无序部分
* 3. 之后每次选取无序部分的第一个元素,作为要排序的元素,将其插入到有序部分
* 4. 因为有序部分是有序的,所以插入过程,可以从有序部分的最后一个数据开始,就是找对应位置,数组元素后移
* @param arr
*/
public static void insertSort(int[] arr){
for(int i=1; i<arr.length; i++){ //从第二个元素开始
int temp = arr[i]; //要插入的第i个元素
int j;
for(j=i-1; j>=0 && temp<arr[j]; j--){
arr[j+1] = arr[j];
}
arr[j+1] = temp;
}
}
/**
* 基数排序
* @param arr
*/
public static void radixSort(int[] arr){
//1. 确定最大位数,决定分配收集的轮数
int times = 1;
int p = 10;
for(int i=0; i<arr.length; i++){
while(arr[i] >= p){
times++;
p *= 10;
}
}
System.out.println(times);
//2. 进行分配 收集操作
int[] temp = new int[arr.length];
int[] bucket = new int[10]; //0-9 共10个桶
int i, j, k;
int radix = 1;
for(i=0; i<times; i++){ //共分配 收集times次
//2.1 每次分配前,都清空桶
for(j=0; j<bucket.length; j++){
bucket[j] = 0;
}
//2.2 将数据分配到桶中:
//具体操作就是依据取余方式,获得对应数位上的数,将对应桶中的数据个数+1
for(j=0; j<arr.length; j++){
k = (arr[j] / radix) % 10;
bucket[k]++;
}
//2.3 确定每个桶中的数据对应的位置
//比如:第2个桶中的数据都比第1个桶中的数据大,设第1个桶中的数据有a个,第2个同中有b个
//那么第2个桶中的的数据的对应位置就是(a, a+b], 在这里计算对应的a+b
//第三个桶对应的位置就是(a+b, a+b+c]
for(j=1; j<10; j++){
bucket[j] = bucket[j-1] + bucket[j];
}
//2.4 收集数据
//首先将数据收集到临时存储对象temp[]中,
//收集数据是从arr[]索引最大处向arr[]索引为0处进行收集
//因为第一次分配 收集之后,数据的对应数位的数值大小是按照从小到大排列的
for(j=arr.length-1; j>=0; j--){
k = (arr[j] / radix) % 10;
temp[bucket[k] -1] = arr[j]; //将对应数据放到对应位置
bucket[k]--;
}
//2.5 将临时数组中的内容复制到arr[]中
for(j = 0; j<arr.length; j++){
arr[j] = temp[j];
}
//2.6 确定下一轮比较的数位
radix = radix * 10;
}
}
/**
* 快速排序
* 1. 先从数列中取出一个数作为基准数。
* 2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
* 3. 再对左右区间重复第二步,直到各区间只有一个数。
* @param arr
* @param low
* @param high
*/
public static void quickSort(int[] arr, int low, int high){
if(low < high){
int i = low;
int j = high;
int key = arr[i]; //归并排序中的基准数(选第一个),temp = arr[i],此时arr[i]处为一个坑
while(i < j){
//从右向左,找小于key的,其索引存放在j中
while(i < j && arr[j] >= key){
j--;
}
//然后将右边大于key的数放到左边,此时key中保存着arr[i], arr[j]填入到arr[i]这个坑中
//arr[j]处产生一个新坑
if(i < j){
arr[i] = arr[j];
i++;
}
//从左向右,找大于key的,其索引存放在i中
while(i < j && arr[i] < key){
i++;
}
//然后将arr[i]处的元素填入到上面产生的坑中,arr[i]处又产生一个坑,等下一轮循环填
if(i < j){
arr[j] = arr[i];
j--;
}
}
//循环条件不成立 i==j
arr[i] = key; //将坑填满
//对左右两个子数组再进行快速排序,递归
quickSort(arr, low, j-1);
quickSort(arr, j+1, high);
}
}
/**
* 归并排序中的归并部分
* 将有序数列arr[first...mid]和arr[mid...last]合并。
* @param arr
* @param first
* @param mid
* @param last
* @param temp
*/
public static void mergeSort_merge(int[] arr, int first, int mid, int last, int[] temp){
int i = first, j = mid+1;
int m = mid, n = last;
int k = 0;
//合并两个arr[]中的两个部分
while(i <= m && j<= n){
if(arr[i] <= arr[j]){
temp[k] = arr[i];
k++;
i++;
}else{
temp[k] = arr[j];
k++;
j++;
}
}
while(i <= m){
temp[k] = arr[i];
k++;
i++;
}
while(j <= n){
temp[k] = arr[j];
k++;
j++;
}
//重新复制到arr[]
for(i=0; i<k; i++){
arr[first+i] = temp[i];
}
}
/**
* 归并排序中的排序部分
* @param arr
* @param first
* @param last
* @param temp
*/
public static void mergeSort_sort(int[] arr, int first, int last, int[] temp){
if(first < last){
int mid = (first + last) / 2;
mergeSort_sort(arr, first, mid, temp);
mergeSort_sort(arr, mid+1, last, temp);
mergeSort_merge(arr, first, mid, last, temp);
}
}
/**
* 归并排序的入口,需要维持一个临时数组对象
* @param arr
*/
public static void mergeSort(int[] arr){
int[] temp = new int[arr.length];
mergeSort_sort(arr, 0, arr.length-1, temp);
}
}
总结
从一个 知乎回答 中偷的一张图:
(1)选择排序的不稳定性:对于数组9* 9 2
,第一次外层循环将数字9*和第三个数字2进行交换,这样就破坏了稳定性。最后结果为2 9 9*
。