一、快速排序
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
1.首先设定一个分界值,通过该分界值将数组分成左右两部分。
2.将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
public class QuickSort {
public static void main(String[] args) {
// int[] arrays = {101, 34, 119, 1};
// int[] result = insertSort(arrays);
// System.out.println(Arrays.toString(result));
//速度测试 8049
long begin = System.currentTimeMillis();
int[] array = new int[8];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 8000000);
}
int[] results = quickSort(array,0,array.length-1);
long end = System.currentTimeMillis();
System.out.println("用时:"+(end - begin));
System.out.println(Arrays.toString(results));
}
public static int[] quickSort(int[]arr,int left,int right){
// System.out.println(Arrays.toString(arr));
//左下标
int lIndex = left;
//右下标
int rIndex = right;
//pivot中轴值
int pivot = arr[(left + right) / 2];
//临时变量
int temp = 0;
//while循环的目的是让比pivot值小放到左边,比pivot大的放到右边
while(lIndex < rIndex){
//pivot的左边一直找,找到>=pivot的值时退出
while (arr[lIndex] < pivot){
lIndex += 1;
}
while (arr[rIndex] > pivot){
rIndex -= 1;
}
// System.out.println(Arrays.toString(arr));
//若lIndex>=rIndex说明左边已经全部都是小于pivot的值,右边已全部都是大于pivot的值
if(lIndex >= rIndex){
break;
}
//进行值的交换
temp = arr[lIndex];
arr[lIndex] = arr[rIndex];
arr[rIndex] = temp;
//交换完成后若arr[lIndex] == pivot 相同,说明pivot左边已完成排序,右边的指针前移
if(arr[lIndex] == pivot){
rIndex -= 1;
}
//交换完成后若arr[rIndex] == pivot 相同,说明pivot右边已完成排序,左边的指针后移
else if(arr[rIndex] == pivot){
lIndex += 1;
}
}
//如果lIndex == rIndex ,需将左指针后移 ,右指针前移 避免出现栈溢出
if(lIndex == rIndex){
lIndex++;
rIndex--;
}
//若右指针比初始的做指针大,说明左边没有进行排序
if(left < rIndex){
quickSort(arr,left,rIndex);
}
if(right > lIndex){
quickSort(arr,lIndex,right);
}
return arr;
}
}
二、归并排序
归并操作的工作原理如下:
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4.重复步骤3直到某一指针超出序列尾
5.将另一序列剩下的所有元素直接复制到合并序列尾
public class MergeSort {
public static void main(String[] args) {
// int[] arrays = {101, 34, 119, 1};
// int[] temp = new int[arrays.length];
// mergeSort(arrays, 0, arrays.length - 1, temp);
// System.out.println(Arrays.toString(arrays));
//速度测试 8049
long begin = System.currentTimeMillis();
int[] array = new int[80000];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 8000000);
}
int[] temp = new int[array.length];
mergeSort(array, 0, array.length - 1, temp);
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - begin));
// System.out.println(Arrays.toString(array));
}
public static void mergeSort(int[] arrays, int left, int right, int[] temp) {
if (left < right) {
int pivot = (left + right) / 2;
mergeSort(arrays, left, pivot, temp);
mergeSort(arrays, pivot + 1, right, temp);
merge(arrays, left, pivot, right, temp);
}
}
public static void merge(int[] arrays, int left, int pivot, int right, int[] temp) {
//初始化左边有序序列的初始索引
int leftIndex = left;
//初始化右边有序序列的初始索引
int rightIndex = pivot + 1;
//指向temp数组的当前索引
int tempIndex = 0;
//一.先把左右两边(有序)的数组按照规则填充到temp数组中
//直到左右两边的有序序列,有一边处理完成为止
while (leftIndex <= pivot && rightIndex <= right) {
if (arrays[leftIndex] <= arrays[rightIndex]) {
temp[tempIndex] = arrays[leftIndex];
leftIndex++;
tempIndex++;
} else {
temp[tempIndex] = arrays[rightIndex];
rightIndex++;
tempIndex++;
}
}
while (leftIndex <= pivot) {
temp[tempIndex] = arrays[leftIndex];
tempIndex++;
leftIndex++;
}
while (rightIndex <= right) {
temp[tempIndex] = arrays[rightIndex];
tempIndex++;
rightIndex++;
}
tempIndex = 0;
int tempLeft = left;
while (tempLeft <= right) {
arrays[tempLeft] = temp[tempIndex];
tempIndex++;
tempLeft++;
}
}
}
三、桶排序/基数排序
基本思想:先排好个位,再排十位,百位,千位…
1.创建10个的桶,下标从0到9。
2.遍历原数据,获取元素的个位,将其放入匹配下标的桶中。
3.全部放入之后再取出替换原数据,再将排序过一次的原数据遍历,获取元素的十位,将其放入匹配下标的桶中,依次百位,千位…
4.最后一次放到桶中,再按照桶的下标从0-9将其中的数据取出,就获得到了有序数列。
public class RadixSort {
public static void main(String[] args) {
/*
int[] arrays = {101, 34, 119, 1};
int[] result = radixSort(arrays);
System.out.println(Arrays.toString(result));
*/
//速度测试 91
long begin = System.currentTimeMillis();
int[] array = new int[8000000];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 8000000);
}
int[] results = radixSort(array);
long end = System.currentTimeMillis();
System.out.println("用时:"+(end - begin));
// System.out.println(Arrays.toString(results));
}
public static int[] radixSort(int[] arrays) {
//数组中最大数
int max = arrays[0];
for (int i = 1; i < arrays.length; i++) {
if (arrays[i] > max) {
max = arrays[i];
}
}
//最大数是几位数
int maxLength = (max + "").length();
// 定义10个桶,每个桶是一个数组
/*说明
1. 二维数组包含10个一维数组
2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arrays.length
3. 明确,基数排序是使用空间换时间的经典算法
*/
int[][] bucket = new int[10][arrays.length];
//定义一个数组记录每个桶实际存放的数据个数
int[] bucketCounts = new int[10];
//取出数据用
int index = 0;
//使用循环进行排序
for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
//针对每个元素对应的位数进行处理,第一次处理个位数,第二次处理十位,以此类推
for (int j = 0; j < arrays.length; j++) {
//取出每个元素对应位数的值
int digitOfElement = arrays[j] / n % 10;
//将其放入对应的桶中
bucket[digitOfElement][bucketCounts[digitOfElement]] = arrays[j];
//将指针向前移动一下
bucketCounts[digitOfElement]++;
}
//按照这个桶的顺序(一维数组的下标依次取出数据,放入到原来的数组中)
index = 0;
//遍历每一个桶中的数据
for (int k = 0; k < bucketCounts.length; k++) {
//只有桶中有数据时才放入原数组
if(bucketCounts[k]!=0){
//循环第k个桶
for (int l = 0;l < bucketCounts[k];l++){
//取出元素放入arrays
arrays[index++] = bucket[k][l];
}
}
//第i+1轮处理后将桶的指针回到初始位置
bucketCounts[k] = 0;
}
}
return arrays;
}
}