import java.util.ArrayList;
import java.util.List;
public class FastSort {
public static void main(String[] args) {
FastSort sort=new FastSort();
System.out.println("各種排序的代碼");
System.out.print("沒排序前的數據 ");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
//這里不想讓所有的方法都是靜態的,所以才用對象去調用
sort.printData(array);
sort.insertSort();//直接插入排序
sort.shellSort();//希爾排序
sort.selectSort();//選擇排序
sort.heapSort();//堆排序
sort.bubbleSort();//冒泡排序
sort.quickSort();//快速排序
sort.mergingSort();//歸並排序
sort.radixSort();//基數排序
}
/**
* 打印數據
*/
private static void printData(int[] array) {
//輸出排列好的數組
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
public static void insertSort() {
System.out.print("\n1.簡單插入排序 :");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
int temp = 0;
for (int i = 1; i < array.length; i++) {
temp = array[i];//選中要插入的數據,每次往下推一個
int j = i - 1; //這里j,后面需要用到,所以抽出來
for (; j >= 0 && temp < array[j]; j--) {//第一個條件也是可以寫,也可以不寫;這個寫法我也是比較難想到,但是如果你把條件抽到括號就不對了
array[j + 1] = array[j]; //將大於temp的值整體后移一個單位
}
array[j + 1] = temp;//這里的已經不是i-1,而是看它對比通過了幾次后的值
}
printData(array);
}
public static void shellSort() {
System.out.print("\n2. 希爾排序:");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
double d1 = array.length;
int temp = 0;
while (true) {
d1 = Math.ceil(d1 / 2);//四舍五入取值
int d = (int) d1;//double類型的數據強轉成int類型,這是“增量”
for (int x = 0; x < d; x++) {//數據分組
for (int i = x + d; i < array.length; i += d) {//各組內的數據進行排序
int j = i - d;
temp = array[i];
for (; j >= 0 && temp < array[j]; j -= d) {//插入數據
array[j + d] = array[j];
}
array[j + d] = temp;
}
}
if (d == 1) //增量為1,並表明所以數據一起排了序,排序完成
break;
}
//輸出排列好的數組
printData(array);
}
/**
* 簡單選擇排序
* 這個思想和代碼都是比較簡單的啦
* 選擇排序就是(從小到大排序)第一次選擇所有數據中最小的數據,和第一個數據交換,然后從剩下的所有數據選擇最小的放在第二個位置,以此類推,就可以得到排列好的數據。
*/
public void selectSort() {
System.out.print("\n3.簡單選擇排序: ");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
int position = 0;
for (int i = 0; i < array.length; i++) {//遍歷所有的數據
position = i;//要遍歷的游標值
int temp = array[i];//該游標值對應的數值
for (int j = i + 1; j < array.length; j++) {//遍歷剩下的數據中的最小值
if (array[j] < temp) {//如果temp比剩下的任何一個數據大,就交換,保證temp是最小的
temp = array[j];
position = j;
}
}
//上面一個for、if保證了temp是剩下數中最小的數,position是最終交換的游標值
//下面兩步是把所有的數據的最小值和剩下數組數據的第一個數組數據數做交換
array[position] = array[i];
array[i] = temp;
}
//輸出排列好的數組
printData(array);
}
/**
* 堆排序
* 堆排序不僅思想上是所有排序中最麻煩的,而且代碼也是!
* 說白了堆排序就是選擇排序的一種,就是不斷選出最大值,最終完成排序。
* 但是這里涉及到一個二叉樹,二叉樹是什么呢?二叉樹就是一個根有兩個節點或一個節點,並且根節點的值一定比支點的值大,就是那么簡單。
* 堆排序就是不斷剔除根節點並不斷重新建堆的過程,直到只剩下一個節點,就完成所有的排序了
*/
public void heapSort() {
System.out.print("\n4. 堆排序:");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
int arrayLength = array.length;
//循環建堆
for (int i = 0; i < arrayLength - 1; i++) {
//建堆
buildMaxHeap(array, arrayLength - 1 - i);
//交換堆頂和最后一個元素
swap(array, 0, arrayLength - 1 - i);
// System.out.println(Arrays.toString(array));//建堆並交換后的數據
}
//輸出排列好的數組
printData(array);
}
private void swap(int[] data, int i, int j) {
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
//對data數組從0到lastIndex建大頂堆
private void buildMaxHeap(int[] data, int lastIndex) {
//從lastIndex處節點(最后一個節點)的父節點開始
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
//k保存正在判斷的節點
int k = i;
//如果當前k節點的子節點存在
while (k * 2 + 1 <= lastIndex) {
//k節點的左子節點的索引
int biggerIndex = 2 * k + 1;
//如果biggerIndex小於lastIndex,即biggerIndex+1代表的k節點的右子節點存在
if (biggerIndex < lastIndex) {
//若果右子節點的值較大
if (data[biggerIndex] < data[biggerIndex + 1]) {
//biggerIndex總是記錄較大子節點的索引
biggerIndex++;
}
}
//如果k節點的值小於其較大的子節點的值
if (data[k] < data[biggerIndex]) {
//交換他們
swap(data, k, biggerIndex);
//將biggerIndex賦予k,開始while循環的下一次循環,重新保證k節點的值大於其左右子節點的值
k = biggerIndex;
} else {
break;
}
}
}
}
/**
* 冒泡排序
* 冒泡排序也是比較簡單的一種,兩兩比較,這個在邏輯上和代碼上都不難想到把
* 一輪冒泡后,得到最小的值放在第一個位置,第二輪對剩下的數據進行冒泡,再把剩下數據中的最小的放在第二個位置,一次類推
* 冒泡排序和選擇排序在一輪后顯示的數據相似,但是過程卻是很不一樣的。冒泡就是不斷的比較,而選擇是從所有的選出其中最小的。
*/
public void bubbleSort() {
System.out.print("\n5. 冒泡排序:");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
int temp = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
//輸出排列好的數組
printData(array);
}
/**
* 快速排序
* 快速排序也是冒泡排序中的一種,但是不一定選中最大或最小值,選中的是任意一個數值,並把它放到適當的游標值的位置,不斷對各組數據冒泡,最終得到排列好的數據
*/
public void quickSort() {
System.out.print("\n6. 快速排序:");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
quick(array);
//輸出排列好的數組
printData(array);
}
private int getMiddle(int[] list, int low, int high) {
int tmp = list[low]; //數組的第一個作為中軸
while (low < high) {
while (low < high && list[high] >= tmp) {
high--;
}
list[low] = list[high]; //比中軸小的記錄移到低端
while (low < high && list[low] <= tmp) {
low++;
}
list[high] = list[low]; //比中軸大的記錄移到高端
}
list[low] = tmp; //中軸記錄到尾
return low; //返回中軸的位置
}
private void _quickSort(int[] list, int low, int high) {
if (low < high) {
int middle = getMiddle(list, low, high); //將list數組進行一分為二
_quickSort(list, low, middle - 1); //對低字表進行遞歸排序
_quickSort(list, middle + 1, high); //對高字表進行遞歸排序
}
}
private void quick(int[] a2) {
if (a2.length > 0) { //查看數組是否為空
_quickSort(a2, 0, a2.length - 1);//里面涉及到不斷循環遍歷
}
}
/**
* 歸並排序
* 其實歸並排序和上面說到的希爾排序是有異曲同工的設計思想,都是先把一部分數據排列好,然后讓一部分數據插入一部分數據,不斷融合,直到完全融合。
*/
public void mergingSort() {
System.out.print("\n7. 歸並排序:");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
sort(array, 0, array.length - 1);
//輸出排列好的數組
printData(array);
}
private void sort(int[] data, int left, int right) {
if (left < right) {
//找出中間索引
int center = (left + right) / 2;
//對左邊數組進行遞歸
sort(data, left, center);
//對右邊數組進行遞歸
sort(data, center + 1, right);
//合並
merge(data, left, center, right);
}
}
private void merge(int[] data, int left, int center, int right) {
int[] tmpArr = new int[data.length];
int mid = center + 1;
//third記錄中間數組的索引
int third = left;
int tmp = left;
while (left <= center && mid <= right) {
//從兩個數組中取出最小的放入中間數組
if (data[left] <= data[mid]) {
tmpArr[third++] = data[left++];
} else {
tmpArr[third++] = data[mid++];
}
}
//剩余部分依次放入中間數組
while (mid <= right) {
tmpArr[third++] = data[mid++];
}
while (left <= center) {
tmpArr[third++] = data[left++];
}
//將中間數組中的內容復制回原數組
while (tmp <= right) {
data[tmp] = tmpArr[tmp++];
}
// System.out.println(Arrays.toString(data));//過程
}
/**
* 基數排序
* 基數排序,比較的是各個數值的位數上的大小
* 相對來說速度也是不錯的,比如第一次就可以比較出只有個位數的數據的大小排列順序,第二次就可以比較出只有十位和各位的數據,以此類推,一直比較,就會比較完所有的數。
*/
public void radixSort() {
System.out.print("\n8. 基數排序:");
int array[] = {34, 18, 54, 5, 4, 69, 99, 98, 54, 56};
sort(array);
//輸出排列好的數組
printData(array);
}
private void sort(int[] array) {
//首先確定排序的趟數;
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
int time = 0;
//判斷位數;
while (max > 0) {
max /= 10;
time++;
}
//建立10個隊列;
List<ArrayList> queue = new ArrayList<ArrayList>();
for (int i = 0; i < 10; i++) {
ArrayList<Integer> queue1 = new ArrayList<Integer>();
queue.add(queue1);
}
//進行time次分配和收集;
for (int i = 0; i < time; i++) {
//分配數組元素;
for (int j = 0; j < array.length; j++) {
//得到數字的第time+1位數;
int x = array[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
ArrayList<Integer> queue2 = queue.get(x);
queue2.add(array[j]);
queue.set(x, queue2);
}
int count = 0;//元素計數器;
//收集隊列元素;
for (int k = 0; k < 10; k++) {
while (queue.get(k).size() > 0) {
ArrayList<Integer> queue3 = queue.get(k);
array[count] = queue3.get(0);
queue3.remove(0);
count++;
}
}
}
}
}