菜鸟教程:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html
两两比较,依次将最大值放在最后一位,倒数第二位。。。
public static void main(String[] args){
int[] arr = {
2,6,4,20,8,3,10};
int temp = 0;
for(int i = 0;i < arr.length - 1;i++){
for(int j = 0;j < arr.length - i - 1;j++){
// 从小到大排序(小于号为从大到小排序)
if(arr[j] > arr[j+1]){
temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 6, 8, 10, 20]
}
// 优化冒泡排序
public static void main(String[] args){
int[] arr = {
2,6,4,20,8,3,10};
int temp = 0;
// 当次循环位置是否有改动 true:有 false:无
boolean flag = false;
for(int i = 0;i < arr.length - 1;i++){
flag = false;
for(int j = 0;j < arr.length - i - 1;j++){
// 从小到大排序(小于号为从大到小排序)
if(arr[j] > arr[j+1]){
temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
flag = true;
}
}
// 当次循环位置是否没有改动即可提前结束循环
if(!false){
break;
}
}
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 6, 8, 10, 20]
}
找到最小值,与第一位交换,然后找到次小值与第二位交换。。。
public static void main(String[] args){
int[] arr = {
2,6,4,20,8,3,10};
// 临时变量
int temp = 0;
// 最小值下标
int index = 0;
for(int i = 0;i < arr.length - 1;i++){
index = i;
for(int j = i + 1;j < arr.length;j++){
// 记录最小值的下标
if(arr[j] < arr[index]){
index = j;
}
}
// 将找到的最小值和i位置所在的值进行交换
if(i != index){
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 6, 8, 10, 20]
}
分为有序和无序两块,每次将无序中的一个按照位置插入有序中,该位置后的有序值均向后移动一位
public static void main(String[] args){
int[] arr = {
2,6,4,20,8,3,10};
// 待插入的值
int temp = 0;
// 角标
int index = 0;
// 循环当前要比较的值
for (int i = 1; i < arr.length; i++) {
temp = arr[i];
index = -1;
// 循环有序列表
for (int j = i; j > 0; j--) {
if (arr[j - 1] > temp){
index = j;
arr[j] = arr[j -1];
}else {
break;
}
}
if (index != -1){
arr[index-1] = temp;
}
}
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 6, 8, 10, 20]
}
希尔排序也是插入排序的一种,只是对希尔算法做了优化,缩小增量排序,希尔算法有交换法和位移法
// 希尔排序交换法
public static void main(String[] args) {
int[] arr = {
2,6,4,20,8,3,10};
int temp = 0;
for (int step = arr.length / 2; step > 0; step /= 2) {
for (int i = step; i < arr.length; i++) {
// 步长为step
for (int j = i - step; j >= 0; j -= step) {
if (arr[j] > arr[j+step]){
temp = arr[j];
arr[j] = arr[j+step];
arr[j+step] = temp;
}
}
}
}
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 6, 8, 10, 20]
}
// 希尔排序位移法
public static void main(String[] args) {
int[] arr = {
2,6,4,20,8,3,10};
int temp = 0;
for (int step = arr.length / 2; step > 0; step /= 2) {
for (int i = step; i < arr.length; i++) {
int j = i;
temp = arr[i];
if (arr[j] < arr[j - step]){
while (j-step >= 0 && temp < arr[j - step]){
arr[j] = arr[j-step];
j -= step;
}
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 6, 8, 10, 20]
}
该算法是采用分治法
public class MergeSort {
/**
* 归并算法
* 合并次数=数组大小-1次
* @param args
*/
public static void main(String[] args) {
int[] arr = {
8,4,5,7,1,3,6,2};
int[] temp = new int[arr.length];
test01(arr,0,arr.length -1,temp);
System.out.println(Arrays.toString(temp));
// 测试归并排序效率
// 八百万数据一秒排列完成
// test02();
}
/**
* 分+合操作
* @param arr
* @param left
* @param right
* @param temp
*/
public static void test01(int[] arr,int left,int right,int[] temp){
if (left < right){
// 找到中间索引
int mid = (left + right) / 2;
// 向左传递进行分解
test01(arr,left,mid,temp);
// 向右传递进行分解
test01(arr,mid+1,right,temp);
// 没分解一次就需要合并一次
merge(arr,left,mid,right,temp);
}
}
/**
* 合并方法
* @param arr 要排列的数组
* @param left 左边索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 临时数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
// 左边初始索引
int l = left;
// 右侧初始索引,中间索引为左侧的边界,所以右侧索引初始化的时候需要加一
int r = mid + 1;
// temp临时数组初始化索引
int t = 0;
// 1、将左右两边有序数组按照规则填充到临时数组
while (l <= mid && r<= right){
// 当左侧值小于等于右侧值时,将最小值(左侧值)放置在temp中
if (arr[l] <= arr[r]){
temp[t] = arr[l];
// 放置之后temp临时数组角标右移,左侧索引右移
t++;
l++;
}else{
// 反之,将最小值(右侧)放置在temp中
temp[t] = arr[r];
// 放置之后temp临时数组角标右移,右侧索引右移
t++;
r++;
}
}
// 2、当其中一侧全部放置在temp临时数组之后,将另一侧剩余数组按序放置在temp临时数组中
// 左侧还有剩余数组
while (l <= mid){
temp[t] = arr[l];
t++;
l++;
}
// 右侧还有剩余数组
while (r <= right){
temp[t] = arr[r];
t++;
r++;
}
// 3、将temp临时数组放置在arr数组中
// 临时数组索引
t = 0;
int t_left = left;
while (t_left <= right){
arr[t_left] = temp[t];
t_left++;
t++;
}
}
/**
* 测试归并排序效率
*/
public static void test02(){
int maxSize = 8000000;
int[] arr = new int[maxSize];
int[] temp = new int[arr.length];
for (int i = 0; i < maxSize; i++) {
arr[i] = (int) (Math.random() * 8000000);
}
long start = System.currentTimeMillis();
System.out.println("执行前时间"+System.currentTimeMillis());
test01(arr,0,arr.length-1,temp);
long end = System.currentTimeMillis();
System.out.println("执行后时间"+System.currentTimeMillis());
System.out.println("程序运行时间: "+(end-start)+"ms");
System.out.println("程序运行时间: "+(end-start)/1000+"s");
}
}
每次定义一个中轴,让将小值放在左侧,大值放在右侧,依次递归左侧和右侧,每次均定义一个中轴
public class QuickSort {
public static void main(String[] args) {
int[] arr = {
1,2,-3,20,45,28,-4,6};
// 定义数组中间的值为中轴
test01(arr,0,arr.length - 1);
// 定义数组中第一个值为中轴
// test02(arr,0,arr.length-1);
System.out.println("数据交换后:"+Arrays.toString(arr));
}
/**
* 定义数组中间的值为中轴
* @param arr
* @param left
* @param right
*/
public static void test01(int[] arr,int left,int right){
// 左角标
int l = left;
// 右角标
int r = right;
// 中轴值
int pivot = arr[(left + right)/2];
// 临时变量用于交换使用
int temp = 0;
// 此循环是为了将比p小的放置在左边,比p大的放置在右边
while (l < r){
// 在左边找大于等于p的值,找到才退出
// arr[l]一直循环下去,可以找到p值,所以不存在死循环
while (arr[l] < pivot){
// 左边角标需要一致右移,所以需要++
l++;
}
// 在右边找小于等于p的值,找到才退出
// arr[r]一直循环下去,可以找到p值,所以不存在死循环
while (arr[r] > pivot){
// 左边角标需要一致左移,所以需要--
r--;
}
// 当左边当角标大于等于右边角标时,说明左边已经全部小于p,右边全部大于p
if (l >= r){
break;
}
// 数据交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
// 交换数据之后arr[l] = pivot时,r--,前移,避免出现数值一样的
if (arr[l] == pivot){
r--;
}
// 交换数据之后arr[r] = pivot时,l++,后移,避免出现数值一样的
if (arr[r] == pivot){
l++;
}
}
// 当l=r时,必须l++ r--,避免栈溢出
if (l == r){
l++;
r--;
}
// 向左递归
if (left < r){
test01(arr,left,r);
}
// 向右递归
if (right > l){
test01(arr,l,right);
}
}
/**
* 定义数组中第一个值为中轴
* @param arr
* @param left
* @param right
*/
public static void test02(int[] arr,int left,int right){
// 递归调用
if (left >= right){
return;
}
// 左边滑动角标
int l = left;
// 右边滑动角标
int r = right;
// 中轴值
int pivot = arr[l];
// 临时变量,用于交换数据是使用
int temp = 0;
while (l < r){
// 右角标移动
while (arr[r] >= pivot && l < r){
r--;
}
if (l < r){
temp = arr[r];
arr[r] = arr[l];
arr[l] = temp;
}
// 左角标移动
while (arr[l] <= pivot && l < r){
l++;
}
if (l < r) {
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
}
// 对中轴左侧做重复操作
test02(arr,left,l-1);
// 对中轴右侧做重复操作
test02(arr,l + 1,right);
}
}
堆分为大顶堆小顶堆,升序使用大顶堆,降序使用小顶堆
public class HeapSort implements IArraySort {
@Override
public int[] sort(int[] sourceArray) throws Exception {
// 对 arr 进行拷贝,不改变参数内容
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
int len = arr.length;
buildMaxHeap(arr, len);
for (int i = len - 1; i > 0; i--) {
swap(arr, 0, i);
len--;
heapify(arr, 0, len);
}
return arr;
}
private void buildMaxHeap(int[] arr, int len) {
for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
heapify(arr, i, len);
}
}
private void heapify(int[] arr, int i, int len) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
swap(arr, i, largest);
heapify(arr, largest, len);
}
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
public class CountingSort implements IArraySort {
@Override
public int[] sort(int[] sourceArray) throws Exception {
// 对 arr 进行拷贝,不改变参数内容
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
int maxValue = getMaxValue(arr);
return countingSort(arr, maxValue);
}
private int[] countingSort(int[] arr, int maxValue) {
int bucketLen = maxValue + 1;
int[] bucket = new int[bucketLen];
for (int value : arr) {
bucket[value]++;
}
int sortedIndex = 0;
for (int j = 0; j < bucketLen; j++) {
while (bucket[j] > 0) {
arr[sortedIndex++] = j;
bucket[j]--;
}
}
return arr;
}
private int getMaxValue(int[] arr) {
int maxValue = arr[0];
for (int value : arr) {
if (maxValue < value) {
maxValue = value;
}
}
return maxValue;
}
}
public class BucketSort implements IArraySort {
private static final InsertSort insertSort = new InsertSort();
@Override
public int[] sort(int[] sourceArray) throws Exception {
// 对 arr 进行拷贝,不改变参数内容
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
return bucketSort(arr, 5);
}
private int[] bucketSort(int[] arr, int bucketSize) throws Exception {
if (arr.length == 0) {
return arr;
}
int minValue = arr[0];
int maxValue = arr[0];
for (int value : arr) {
if (value < minValue) {
minValue = value;
} else if (value > maxValue) {
maxValue = value;
}
}
int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;
int[][] buckets = new int[bucketCount][0];
// 利用映射函数将数据分配到各个桶中
for (int i = 0; i < arr.length; i++) {
int index = (int) Math.floor((arr[i] - minValue) / bucketSize);
buckets[index] = arrAppend(buckets[index], arr[i]);
}
int arrIndex = 0;
for (int[] bucket : buckets) {
if (bucket.length <= 0) {
continue;
}
// 对每个桶进行排序,这里使用了插入排序
bucket = insertSort.sort(bucket);
for (int value : bucket) {
arr[arrIndex++] = value;
}
}
return arr;
}
/**
* 自动扩容,并保存数据
*
* @param arr
* @param value
*/
private int[] arrAppend(int[] arr, int value) {
arr = Arrays.copyOf(arr, arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}
/**
* 基数排序
* 考虑负数的情况还可以参考: https://code.i-harness.com/zh-CN/q/e98fa9
*/
public class RadixSort implements IArraySort {
@Override
public int[] sort(int[] sourceArray) throws Exception {
// 对 arr 进行拷贝,不改变参数内容
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
int maxDigit = getMaxDigit(arr);
return radixSort(arr, maxDigit);
}
/**
* 获取最高位数
*/
private int getMaxDigit(int[] arr) {
int maxValue = getMaxValue(arr);
return getNumLenght(maxValue);
}
private int getMaxValue(int[] arr) {
int maxValue = arr[0];
for (int value : arr) {
if (maxValue < value) {
maxValue = value;
}
}
return maxValue;
}
protected int getNumLenght(long num) {
if (num == 0) {
return 1;
}
int lenght = 0;
for (long temp = num; temp != 0; temp /= 10) {
lenght++;
}
return lenght;
}
private int[] radixSort(int[] arr, int maxDigit) {
int mod = 10;
int dev = 1;
for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
// 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10)
int[][] counter = new int[mod * 2][0];
for (int j = 0; j < arr.length; j++) {
int bucket = ((arr[j] % mod) / dev) + mod;
counter[bucket] = arrayAppend(counter[bucket], arr[j]);
}
int pos = 0;
for (int[] bucket : counter) {
for (int value : bucket) {
arr[pos++] = value;
}
}
}
return arr;
}
/**
* 自动扩容,并保存数据
*
* @param arr
* @param value
*/
private int[] arrayAppend(int[] arr, int value) {
arr = Arrays.copyOf(arr, arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}