Java深入了解數(shù)據(jù)結(jié)構(gòu)中常見(jiàn)的排序算法
一,概念
1,排序
排序,就是使一串記錄,按照其中的某個(gè)或某些關(guān)鍵字的大小,遞增或遞減的排列起來(lái)的操作。 平時(shí)的上下文中,如果提到排序,通常指的是排升序(非降序)。 通常意義上的排序,都是指的原地排序(in place sort)。
2,穩(wěn)定性
兩個(gè)相等的數(shù)據(jù),如果經(jīng)過(guò)排序后,排序算法能保證其相對(duì)位置不發(fā)生變化,則我們稱該算法是具備穩(wěn)定性的排序算法。

或者我們說(shuō)沒(méi)有跳躍的排序也是穩(wěn)定的排序

二,排序詳解

1,插入排序
①直接插入排序
整個(gè)區(qū)間被分為
1. 有序區(qū)間
2. 無(wú)序區(qū)間
每次選擇無(wú)序區(qū)間的第一個(gè)元素,在有序區(qū)間內(nèi)選擇合適的位置插入

public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
insertSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 時(shí)間復(fù)雜度:
* 最好:O(N) -> 數(shù)據(jù)是有序的
* 最壞:O(N^2) -> 無(wú)序的數(shù)據(jù)
* 空間復(fù)雜度:O(1)
* 穩(wěn)定性:穩(wěn)定排序
* @param array
*/
public static void insertSort(int[] array) {
for(int i = 1;i < array.length;i++) {//n-1
int tmp = array[i];
int j = i-1;
for(; j >= 0;j--) {//n-1
if(array[j] > tmp) {
array[j+1] = array[j];
}else{
//array[j+1] = tmp;
break;
}
}
array[j+1] = tmp;
}
}
②希爾排序
希爾排序法又稱縮小增量法。希爾排序法的基本思想是:先選定一個(gè)整數(shù),把待排序文件中所有記錄分成個(gè)組,所有 距離為的記錄分在同一組內(nèi),并對(duì)每一組內(nèi)的記錄進(jìn)行排序。然后,取,重復(fù)上述分組和排序的工作。當(dāng)?shù)竭_(dá)=1時(shí), 所有記錄在統(tǒng)一組內(nèi)排好序。
1. 希爾排序是對(duì)直接插入排序的優(yōu)化。
2. 當(dāng)gap > 1時(shí)都是預(yù)排序,目的是讓數(shù)組更接近于有序。當(dāng)gap == 1時(shí),數(shù)組已經(jīng)接近有序的了,這樣就會(huì)很 快。這樣整體而言,可以達(dá)到優(yōu)化的效果。我們實(shí)現(xiàn)后可以進(jìn)行性能測(cè)試的對(duì)比。


/**
* 時(shí)間復(fù)雜度:不好算 n^1.3 - n^1.5 之間
* 空間復(fù)雜度:O(1)
* 穩(wěn)定性:不穩(wěn)定的排序
* 技巧:如果在比較的過(guò)程當(dāng)中 沒(méi)有發(fā)生跳躍式的交換 那么就是穩(wěn)定的
* @param array
*
*
* @param array 排序的數(shù)組
* @param gap 每組的間隔 -》 組數(shù)
*/
public static void shell(int[] array,int gap) {
for (int i = gap; i < array.length; i++) {
int tmp = array[i];
int j = i-gap;
for (; j >= 0; j -= gap) {
if(array[j] > tmp) {
array[j+gap] = array[j];
}else {
break;
}
}
array[j+gap] = tmp;
}
}
public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
shell(array,5);
System.out.println(Arrays.toString(array));
}
2,選擇排序
①直接選擇排序
每一次從無(wú)序區(qū)間選出最大(或最小)的一個(gè)元素,存放在無(wú)序區(qū)間的最后(或最前),直到全部待排序的數(shù)據(jù)元素排完 。

public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
selectSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 時(shí)間復(fù)雜度:
* 最好:O(N^2)
* 最壞:O(N^2)
* 空間復(fù)雜度:O(1)
* 穩(wěn)定性:不穩(wěn)定的
* @param array
*/
public static void selectSort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i+1; j < array.length; j++) {
if(array[j] < array[i]) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
}
②堆排序
基本原理也是選擇排序,只是不在使用遍歷的方式查找無(wú)序區(qū)間的最大的數(shù),而是通過(guò)堆來(lái)選擇無(wú)序區(qū)間的最大的數(shù)。
注意: 排升序要建大堆;排降序要建小堆。

public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
heapSort(array);
System.out.println(Arrays.toString(array));
}
public static void siftDown(int[] array,int root,int len) {
int parent = root;
int child = 2*parent+1;
while (child < len) {
if(child+1 < len && array[child] < array[child+1]) {
child++;
}
//child的下標(biāo)就是左右孩子的最大值下標(biāo)
if(array[child] > array[parent]) {
int tmp = array[child];
array[child] = array[parent];
array[parent] = tmp;
parent = child;
child = 2*parent+1;
}else {
break;
}
}
}
public static void createHeap(int[] array) {
//從小到大排序 -》 大根堆
for (int i = (array.length-1 - 1) / 2; i >= 0 ; i--) {
siftDown(array,i,array.length);
}
}
/**
* 時(shí)間復(fù)雜度:O(N*logN) 都是這個(gè)時(shí)間復(fù)雜度
* 復(fù)雜度:O(1)
* 穩(wěn)定性:不穩(wěn)定的排序
* @param array
*/
public static void heapSort(int[] array) {
createHeap(array);//O(n)
int end = array.length-1;
while (end > 0) {//O(N*logN)
int tmp = array[end];
array[end] = array[0];
array[0] = tmp;
siftDown(array,0,end);
end--;
}
}
3,交換排序
①冒泡排序
在無(wú)序區(qū)間,通過(guò)相鄰數(shù)的比較,將最大的數(shù)冒泡到無(wú)序區(qū)間的最后,持續(xù)這個(gè)過(guò)程,直到數(shù)組整體有序

public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
bubbleSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 時(shí)間復(fù)雜度:
* 最好最壞都是O(n^2)
* 空間復(fù)雜度:O(1)
* 穩(wěn)定性:穩(wěn)定的排序
* 冒泡 直接插入
* @param array
*/
public static void bubbleSort(int[] array) {
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]) {
int tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
}
}
}
}
②快速排序
1. 從待排序區(qū)間選擇一個(gè)數(shù),作為基準(zhǔn)值(pivot);
2. Partition: 遍歷整個(gè)待排序區(qū)間,將比基準(zhǔn)值小的(可以包含相等的)放到基準(zhǔn)值的左邊,將比基準(zhǔn)值大的(可 以包含相等的)放到基準(zhǔn)值的右邊;
3. 采用分治思想,對(duì)左右兩個(gè)小區(qū)間按照同樣的方式處理,直到小區(qū)間的長(zhǎng)度 == 1,代表已經(jīng)有序,或者小區(qū)間 的長(zhǎng)度 == 0,代表沒(méi)有數(shù)據(jù)。

public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
quickSort1(array);
System.out.println(Arrays.toString(array));
}
public static int partition(int[] array,int low,int high) {
int tmp = array[low];
while (low < high) {
while (low < high && array[high] >= tmp) {
high--;
}
array[low] = array[high];
while (low < high && array[low] <= tmp) {
low++;
}
array[high] = array[low];
}
array[low] = tmp;
return low;
}
public static void quick(int[] array,int start,int end) {
if(start >= end) {
return;
}
int mid = (start+end)/2;
int pivot = partition(array,start,end);
quick(array,start,pivot-1);
quick(array,pivot+1,end);
}
/**
* 時(shí)間復(fù)雜度:
* 最好:O(n*logn) 均勻的分割下
* 最壞:o(n^2) 數(shù)據(jù)有序的時(shí)候
* 空間復(fù)雜度:
* 最好:logn
* 最壞:O(n)
* 穩(wěn)定性:不穩(wěn)定的排序
*
* k*n*logn
* 2
* 1.2
* @param array
*/
public static void quickSort1(int[] array) {
quick(array,0,array.length-1);
}
4,歸并排序
歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個(gè)非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子 序列段間有序。若將兩個(gè)有序表合并成一個(gè)有序表,稱為二路歸并。

public static void main(String[] args) {
int[] array = {12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
mergeSort1(array);
System.out.println(Arrays.toString(array));
}
public static void merge(int[] array,int low,int mid,int high) {
int s1 = low;
int e1 = mid;
int s2 = mid+1;
int e2 = high;
int[] tmp = new int[high-low+1];
int k = 0;//代表tmp數(shù)組的下標(biāo)
while (s1 <= e1 && s2 <= e2) {
if(array[s1] <= array[s2]) {
tmp[k++] = array[s1++];
}else {
tmp[k++] = array[s2++];
}
}
//有2種情況
while (s1 <= e1){
//說(shuō)明第2個(gè)歸并段沒(méi)有了數(shù)據(jù) 把第1個(gè)歸并段剩下的數(shù)據(jù) 全部拷貝過(guò)來(lái)
tmp[k++] = array[s1++];
}
while (s2 <= e2) {
//說(shuō)明第1個(gè)歸并段沒(méi)有了數(shù)據(jù) 把第2個(gè)歸并段剩下的數(shù)據(jù) 全部拷貝過(guò)來(lái)
tmp[k++] = array[s2++];
}
//tmp數(shù)組當(dāng)中 存儲(chǔ)的就是當(dāng)前歸并好的數(shù)據(jù)
for (int i = 0; i < tmp.length; i++) {
array[i+low] = tmp[i];
}
}
public static void mergeSortInternal(int[] array,int low,int high) {
if(low >= high) {
return;
}
int mid = (low+high) / 2;
mergeSortInternal(array,low,mid);
mergeSortInternal(array,mid+1,high);
//合并的過(guò)程
merge(array,low,mid,high);
}
/**
* 時(shí)間復(fù)雜度: O(N*log n)
* 空間復(fù)雜度:O(N)
* 穩(wěn)定性:穩(wěn)定的
* @param array
*/
public static void mergeSort1(int[] array) {
mergeSortInternal(array, 0,array.length-1);
}
到此這篇關(guān)于Java深入了解數(shù)據(jù)結(jié)構(gòu)中常見(jiàn)的排序算法的文章就介紹到這了,更多相關(guān)Java 排序算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaWeb簡(jiǎn)單用戶登錄注冊(cè)實(shí)例代碼(有驗(yàn)證碼)
這篇文章主要介紹了JavaWeb簡(jiǎn)單用戶登錄注冊(cè)實(shí)例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
mybatis源碼解讀之executor包語(yǔ)句處理功能
這篇文章主要介紹了executor包語(yǔ)句處理功能,mybatis中支持三種語(yǔ)句類型,不同語(yǔ)句類型支持的變量符號(hào)不同,下文詳細(xì)內(nèi)容,需要的小伙伴可以參考一下2022-02-02
IDEA中的maven沒(méi)有dependencies解決方案
這篇文章主要介紹了IDEA中的maven沒(méi)有dependencies解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
詳解log4j-over-slf4j與slf4j-log4j12共存stack overflow異常分析
這篇文章主要介紹了詳解log4j-over-slf4j與slf4j-log4j12共存stack overflow異常分析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Java關(guān)鍵字volatile知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是一篇關(guān)于Java關(guān)鍵字volatile知識(shí)點(diǎn)總結(jié)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)參考下。2021-01-01
java 非對(duì)稱加密算法RSA實(shí)現(xiàn)詳解
這篇文章主要介紹了java 非對(duì)稱加密算法RSA實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
Java實(shí)現(xiàn)將漢字轉(zhuǎn)化為漢語(yǔ)拼音的方法
這篇文章主要介紹了Java實(shí)現(xiàn)將漢字轉(zhuǎn)化為漢語(yǔ)拼音的方法,實(shí)例演示了Java引用pinyin4j庫(kù)實(shí)現(xiàn)漢子轉(zhuǎn)化成拼音的使用技巧,需要的朋友可以參考下2015-12-12
SpringMVC攔截器創(chuàng)建配置及執(zhí)行順序
這篇文章主要為大家介紹了SpringMVC攔截器創(chuàng)建配置及執(zhí)行順序,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05

