package com.wschase.sort;
import java.util.Stack;
/**7種排序算法
* Author:WSChase
* Created:2019/4/12
*/
public class Solution {
//在進行下面的排序算法之前我們先寫一下數組打印的方法方便後面的測試
public void printArray(int[] array,int size){
for(int i=0;i<size;i++){
System.out.println(array[i]);
}
}
/**
* 1.直接插入排序
* 最壞時間複雜度:O(n^2)
* 最好時間複雜度:O(n)
* 空間複雜度:O(1)
* 穩定性:穩定
*/
public void insertintoSort(int[] array,int size){
//直接插入排序最重要的就是要知道我們每次進行的是從後面往前面進行插入
//前面的已經是有序的了,所以我們插入的數據只需要往前比較一個就可以。
for(int i=1;i<size;i++){//i從1開始是因爲,如果第一個數插入的是下標爲0的數那麼這個數就不需要
//進行比較,直接進行插入就可以了。
int temp=array[i];
int j;
for(j=i-1;j>=0;j--){
if(array[j]<=temp){
//如果前面的數比插入的數小,那麼我們不需要做操作,直接進行插入就可以
break;
}
//否則將前面較大的數挪到後面,然後將需要插入的數插入到j這個位置
array[j+1]=array[j];
}
//因爲前面的j一直處於循環在改變,所以最後這個j不滿足條件的時候是在空格的前一個位置
//而我們需要插入的位置是在空格位置,所以我們需要將j+1纔可以進行賦值。
array[j+1]=temp;
}
}
/**
* 2.歸併排序
* 最壞時間複雜度:O(n*log(n))
* 最好時間複雜度:O(n*log(n))
* 空間複雜度:O(n)
* 穩定性:穩定
*/
//實現歸併排序
public void _megerSort(int[] array,int left,int right){
//遞歸的終止條件:如果裏面只有一個元素或者沒有元素了那麼就不需要進行排序了
if(right<=left+1){
return;
}
//如果不滿足那麼將區間分爲兩個區間
int mid=left+(right-left)/2;
_megerSort(array,left,mid);
_megerSort(array,mid,right);
//當我們經過上面的排序以後就已經將一個數組排序爲左右兩邊都是有序的了,所以我們直接將它們進行合併即可
meger(array,left,mid,right);
}
//合併兩個有序的數組
public void meger(int[] arrray,int left,int mid,int right){
//首先我們要想清楚的是在合併的時候我們需要一個額外的數組空間將已經排序號的數組進行存放
int size=right-left;
int[] extra=new int[size];
int left_index=left;
int right_index=mid;
int extra_index=0;
//這兩個區間是:[left,mid),[mid,right)
while (left_index<mid&&right_index<right){
if(arrray[left_index]<=arrray[right_index]){
extra[extra_index]=arrray[left_index];
left_index++;
}else {
extra[extra_index]=arrray[right_index];
right_index++;
}
//不管是哪種情況,它的下標都需要進行加1操作
extra_index++;
}
while (left_index<mid){
//如果只有一個條件滿足,那麼就直接將數組拷貝過去
extra[extra_index++]=arrray[left_index++];
}
while (right_index<right){
extra[extra_index++]=arrray[right_index++];
}
//然後將排好序的數組再拷貝回去
for(int i=0;i<size;i++){
arrray[left+i]=extra[i];
}
}
//實現歸併排序
public void megeSort(int[] arrray,int size){
//這是一個左閉右開的區間
_megerSort(arrray,0,size);
}
/**
* 3.快速排序
* 最好時間複雜度:
* 最壞時間複雜度:
* 空間複雜度:
* 穩定性:
*/
public static void quickSort(int[] arr,int low,int high){
int i,j,temp;
if(low>high){
return;
}
i=low;//左邊哨兵的索引
j=high;//右邊哨兵的索引
//temp就是基準位
temp = arr[low];//以最左邊爲 基準位
while (i<j) {
//先看右邊,依次往左遞減
//先從右往左找一個小於 基準位的數
//當右邊的哨兵位置所在的數>基準位的數 時
//繼續從右往左找(同時 j 索引-1)
//找到後會跳出 while循環
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左邊,依次往右遞增
//步驟和上面類似
while (temp>=arr[i]&&i<j) {
i++;
}
//如果滿足條件則交換
if (i<j) {
//z、y 都是臨時參數,用於存放 左右哨兵 所在位置的數據
int z = arr[i];
int y = arr[j];
//左右哨兵 交換數據(互相持有對方的數據)
arr[i] = y;
arr[j] = z;
}
}
//這時 跳出了 “while (i<j) {}” 循環
//說明 i=j 左右在同一位置
//最後將基準爲與i和j相等位置的數字交換
arr[low] = arr[i];//或 arr[low] = arr[j];
arr[i] = temp;//或 arr[j] = temp;
//i=j
//這時左半數組<(i或j所在索引的數)<右半數組
//也就是說(i或j所在索引的數)已經確定排序位置, 所以就不用再排序了,
// 只要用相同的方法 分別處理 左右數組就可以了
// 遞歸調用左半數組
quickSort(arr, low, j-1);
//遞歸調用右半數組
quickSort(arr, j+1, high);
}
//真正調用快速排序方法
public void quickSort1(int[] array,int size){
quickSort(array,0,size-1);
}
/**
* 4.冒泡排序
* 最好時間複雜度:O(n)
* 最壞時間複雜度:O(n^2)
* 空間複雜度:O(1)
* 穩定性:穩定
*/
public void bubbleSort(int[] array,int size){
//這個是用來標記冒泡排序是否需要進行
for(int i=1;i<size;i++){//這個i表示一共需要進行多少趟的排序
int sorted=1;
for(int j=0;j<size-1;j++){//這個j表示進行一趟的排序需要進行多少次
if(array[j]>array[j+1]){
//做這個交換過程是爲了讓小數排在前面,大數排在後面
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
sorted=0;
}
}
if(sorted==1){//表示沒有經過上面的交換過程
break;
}
}
}
/**
* 5.選擇排序
*
*/
public void selectSort(int[] array,int size){
for(int i=1;i<size;i++){
//我們暫且選下標3作爲最大值的數組元素的下標
int max=0;
for(int j=0;j<=size-i;j++){
if(array[j]>array[max]){//將數組中的元素從前到後一次遍歷與最大值進行比較
max=j;
}
}
//進行完一輪最大值的篩選之後就將最大值賦值到數組的最後面:每次的最後面是size-i這個數組下標對應的值
int temp=array[size-i];
array[size-i]=array[max];//進行完一輪比較之後將最大值放在數組最後面
array[max]=temp;
}
}
/**
* 6.希爾排序:希爾排序就是直接排序的升級版
*/
//首先我們將間隔排序寫出來
public void insertWihGapSort(int[] array,int size,int gap){
//間隔排序就是將直接排序的起點改爲間隔
for(int i=gap;i<size;i++){
int k=array[i];//這個表示需要插入的數
int j;
//將需要插入的數和前面間隔爲gap的數進行比較
for(j=i-gap;j>=0;j-=gap){
if(array[j]<=k){
//如果前面的數比要插入的數小,就不需要管
break;
}
//否則將前面的數往後移動
array[j+gap]=array[j];
}
//經過這一輪比較之後需要將要插入的數插入到對應的位置
array[j+gap]=k;
}
}
//下面再進行希爾排序
public void shellSort(int[] array,int size){
int gap=size;
while (true){
gap=(gap/3)+1;
insertWihGapSort(array,size,gap);
if(gap==1){
break;
}
}
}
/**
* 7.堆排序
*/
public static void heapSort(int []arr){
//1.構建大頂堆
for(int i=arr.length/2-1;i>=0;i--){
//從第一個非葉子結點從下至上,從右至左調整結構
adjustHeap(arr,i,arr.length);
}
//2.調整堆結構+交換堆頂元素與末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//將堆頂元素與末尾元素進行交換
adjustHeap(arr,0,j);//重新對堆進行調整
}
}
/**
* 調整大頂堆(僅是調整過程,建立在大頂堆已構建的基礎上)
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出當前元素i
for(int k=i*2+1;k<length;k=k*2+1){//從i結點的左子結點開始,也就是2i+1處開始
if(k+1<length && arr[k]<arr[k+1]){//如果左子結點小於右子結點,k指向右子結點
k++;
}
if(arr[k] >temp){//如果子節點大於父節點,將子節點值賦給父節點(不用進行交換)
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//將temp值放到最終的位置
}
/**
* 交換元素
* @param arr
* @param a
* @param b
*/
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
/**
* 測試
* @param args
*/
public static void main(String[] args) {
Solution s=new Solution();
int[] array=new int[]{1,5,9,3,2,8,7,3};
//(1)直接插入排序
// s.insertintoSort(array,array.length) ;
//(2)歸併排序
// s.megeSort(array,array.length);
//(3)快速排序
s.quickSort1(array,array.length);
//(4)冒泡排序
// s.bubbleSort(array,array.length);
//(5)選擇排序
// s.selectSort(array,array.length);
//(6)希爾排序
// s.shellSort(array,array.length);
//(7)堆排序
// s.heapSort(array);
s.printArray(array,array.length);
}
}
java實現七種常見排序算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.