氣泡排序就這麼簡單
八大排序總結
2.1氣泡排序
思路:
-
倆倆交換,大的放在後面,第一次排序後最大值已在陣列末尾。
-
因為倆倆交換,需要
n-1
趟排序,比如10個數,需要9趟排序
程式碼實現要點:
-
兩個for迴圈,外層迴圈控制排序的趟數,內層迴圈控制比較的次數
-
每趟過後,比較的次數都應該要減1
-
優化:如果一趟排序後也沒有交換位置,那麼該陣列已有序~
//外層迴圈是排序的趟數
for
(int i
=
0
; i
< arrays
.length
-
1
; i
++
)
{
//每比較一趟就重新初始化為0
isChange
=
0
;
//內層迴圈是當前趟數需要比較的次數
for
(int j
=
0
; j
< arrays
.length
- i
-
1
; j
++
)
{
//前一位與後一位與前一位比較,如果前一位比後一位要大,那麼交換
if
(arrays
[j
]
> arrays
[j
+
1
]
)
{
temp
= arrays
[j
]
;
arrays
[j
]
= arrays
[j
+
1
]
;
arrays
[j
+
1
]
= temp
;
//如果進到這裡面了,說明發生置換了
isChange
=
1
;
}
}
//如果比較完一趟沒有發生置換,那麼說明已經排好序了,不需要再執行下去了
if
(isChange
==
0
)
{
break
;
}
}
System
.out
.
println
(
"Hello World"
+ arrays
)
;
2.2選擇排序
思路:
-
找到陣列中最大的元素,與陣列最後一位元素交換
-
當只有一個數時,則不需要選擇了,因此需要
n-1
趟排序,比如10個數,需要9趟排序
程式碼實現要點:
-
兩個for迴圈,外層迴圈控制排序的趟數,內層迴圈找到當前趟數的最大值,隨後與當前趟陣列最後的一位元素交換
//外層迴圈控制需要排序的趟數
for
(int i
=
0
; i
< arrays
.length
-
1
; i
++
)
{
//新的趟數、將角標重新賦值為0
pos
=
0
;
//內層迴圈控制遍歷陣列的個數並得到最大數的角標
for
(int j
=
0
; j
< arrays
.length
- i
; j
++
)
{
if
(arrays
[j
]
> arrays
[pos
]
)
{
pos
= j
;
}
}
//交換
temp
= arrays
[pos
]
;
arrays
[pos
]
= arrays
[arrays
.length
-
1
- i
]
;
arrays
[arrays
.length
-
1
- i
]
= temp
;
}
System
.out
.
println
(
"Hello World"
+ arrays
)
;
2.3插入排序
思路:
-
將一個元素插入到已有序的陣列中,在初始時未知是否存在有序的資料,因此將元素 第一個元素看成是有序的
-
與有序的陣列進行比較, 比它大則直接放入,比它小則移動陣列元素的位置,找到個合適的位置插入
-
當只有一個數時,則不需要插入了,因此需要
n-1
趟排序,比如10個數,需要9趟排序
程式碼實現:
-
一個for迴圈內嵌一個while迴圈實現,外層for迴圈控制需要排序的趟數,while迴圈找到合適的插入位置(並且插入的位置不能小於0)
//臨時變數
int temp
;
//外層迴圈控制需要排序的趟數(從1開始因為將第0位看成了有序資料)
for
(
int i
=
1
; i
< arrays
.length
; i
++
)
{
temp
= arrays
[i
]
;
//如果前一位(已排序的資料)比當前資料要大,那麼就進入迴圈比較[參考第二趟排序]
int j
= i
-
1
;
while
(
j
>=
0
&& arrays
[j
]
> temp
)
{
//往後退一個位置,讓當前資料與之前前位進行比較
arrays
[j
+
1
]
= arrays
[j
]
;
//不斷往前,直到退出迴圈
j
--
;
}
//退出了迴圈說明找到了合適的位置了,將當前資料插入合適的位置中
arrays
[j
+
1
]
= temp
;
}
System
.out
.
println
(
"Hello World"
+ arrays
)
;
2.4快速排序
思路:
-
在陣列中找一個元素(節點),比它小的放在節點的左邊,比它大的放在節點右邊。一趟下來,比節點小的在左邊,比節點大的在右邊。
-
不斷執行這個操作....
程式碼實現:
-
快速排序用遞迴比較好寫【如果不太熟悉遞迴的同學可到:
】。支點取中間,使用L和R表示陣列的最小和最大位置 -
不斷進行比較,直到找到比支點小(大)的數,隨後交換,不斷減小範圍~
-
遞迴L到支點前一個元素(j)(執行相同的操作,同上)
-
遞迴支點後一個元素(i)到R元素(執行相同的操作,同上)
/**
* 快速排序
*
* @param arr
* @param L 指向陣列第一個元素
* @param R 指向陣列最後一個元素
*/
public
static
void
quickSort
(
int
[
] arr
, int
L
, int
R
)
{
int i
=
L
;
int j
=
R
;
//支點
int pivot
= arr
[
(
L
+
R
)
/
2
]
;
//左右兩端進行掃描,只要兩端還沒有交替,就一直掃描
while
(i
<= j
)
{
//尋找直到比支點大的數
while
(pivot
> arr
[i
]
)
i
++
;
//尋找直到比支點小的數
while
(pivot
< arr
[j
]
)
j
--
;
//此時已經分別找到了比支點小的數(右邊)、比支點大的數(左邊),它們進行交換
if
(i
<= j
)
{
int temp
= arr
[i
]
;
arr
[i
]
= arr
[j
]
;
arr
[j
]
= temp
;
i
++
;
j
--
;
}
}
//上面一個while保證了第一趟排序支點的左邊比支點小,支點的右邊比支點大了。
//“左邊”再做排序,直到左邊剩下一個數(遞迴出口)
if
(
L
< j
)
quickSort
(arr
,
L
, j
)
;
//java學習交流:737251827 進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
//“右邊”再做排序,直到右邊剩下一個數(遞迴出口)
if
(i
<
R
)
quickSort
(arr
, i
,
R
)
;
}
2.5歸併排序
思路:
-
將兩個已排好序的陣列合併成一個有序的陣列。
-
將元素分隔開來,看成是有序的陣列,進行比較合併
-
不斷拆分和合並,直到只有一個元素
程式碼實現:
-
在第一趟排序時實質是兩個元素(看成是兩個已有序的陣列)來進行合併,不斷執行這樣的操作,最終陣列有序
-
拆分左邊,右邊,合併...
public
static
void
main
(
String
[
] args
)
{
int
[
] arrays
=
{
9
,
2
,
5
,
1
,
3
,
2
,
9
,
5
,
2
,
1
,
8
}
;
mergeSort
(arrays
,
0
, arrays
.length
-
1
)
;
System
.out
.
println
(
"Hello World"
+ arrays
)
;
}
/**
* 歸併排序
* @param arrays
* @param L 指向陣列第一個元素
* @param R 指向陣列最後一個元素
*/
public
static
void
mergeSort
(
int
[
] arrays
, int
L
, int
R
)
{
//如果只有一個元素,那就不用排序了
if
(
L
==
R
)
{
return
;
}
else
{
//取中間的數,進行拆分
int
M
=
(
L
+
R
)
/
2
;
//左邊的數不斷進行拆分
mergeSort
(arrays
,
L
,
M
)
;
//右邊的數不斷進行拆分
mergeSort
(arrays
,
M
+
1
,
R
)
;
//合併
merge
(arrays
,
L
,
M
+
1
,
R
)
;
}
}
/**
* 合併陣列
* @param arrays
* @param L 指向陣列第一個元素
* @param M 指向陣列分隔的元素
* @param R 指向陣列最後的元素
*/
public
static
void
merge
(
int
[
] arrays
, int
L
, int
M
, int
R
)
{
//左邊的陣列的大小
int
[
] leftArray
=
new
int
[
M
-
L
]
;
//右邊的陣列大小
int
[
] rightArray
=
new
int
[
R
-
M
+
1
]
;
//往這兩個陣列填充資料
for
(int i
=
L
; i
<
M
; i
++
)
{
leftArray
[i
-
L
]
= arrays
[i
]
;
}
for
(int i
=
M
; i
<=
R
; i
++
)
{
rightArray
[i
-
M
]
= arrays
[i
]
;
}
int i
=
0
, j
=
0
;
// arrays陣列的第一個元素
int k
=
L
;
//比較這兩個陣列的值,哪個小,就往陣列上放
while
(i
< leftArray
.length
&& j
< rightArray
.length
)
{
//誰比較小,誰將元素放入大陣列中,移動指標,繼續比較下一個
if
(leftArray
[i
]
< rightArray
[j
]
)
{
arrays
[k
]
= leftArray
[i
]
;
i
++
;
k
++
;
}
else
{
arrays
[k
]
= rightArray
[j
]
;
j
++
;
k
++
;
}
}
//如果左邊的陣列還沒比較完,右邊的數都已經完了,那麼將左邊的數抄到大陣列中(剩下的都是大數字)
while
(i
< leftArray
.length
)
{
arrays
[k
]
= leftArray
[i
]
;
i
++
;
k
++
;
}
//如果右邊的陣列還沒比較完,左邊的數都已經完了,那麼將右邊的數抄到大陣列中(剩下的都是大數字)
while
(j
< rightArray
.length
)
{
arrays
[k
]
= rightArray
[j
]
;
k
++
;
j
++
;
}
}
《為什麼我牆裂建議大家使用列舉來實現單例。》
2.6堆排序
思路:
-
堆排序使用到了完全二叉樹的一個特性【不瞭解二叉樹的同學可到:
學習一波】,根節點比左孩子和右孩子都要大,完成 一次建堆的操作實質上是比較根節點和左孩子、右孩子的大小,大的交換到根節點上, 直至最大的節點在樹頂 -
隨後與陣列最後一位元素進行交換
-
......
程式碼實現:
-
只要左子樹或右子樹大於當前根節點,則替換。替換後會導致下面的子樹發生了變化,因此同樣需要進行比較,直至各個節點實現父>子這麼一個條件
public
static
void
main
(
String
[
] args
)
{
int
[
] arrays
=
{
6
,
3
,
8
,
7
,
5
,
1
,
2
,
23
,
4321
,
432
,
3
,
2
,
34234
,
2134
,
1234
,
5
,
132423
,
234
,
4
,
2
,
4
,
1
,
5
,
2
,
5
}
;
for
(int i
=
0
; i
< arrays
.length
; i
++
)
{
//每完成一次建堆就可以排除一個元素了
maxHeapify
(arrays
, arrays
.length
- i
)
;
//交換
int temp
= arrays
[
0
]
;
arrays
[
0
]
= arrays
[
(arrays
.length
-
1
)
- i
]
;
arrays
[
(arrays
.length
-
1
)
- i
]
= temp
;
}
System
.out
.
println
(
"Hello World"
+ arrays
)
;
}
/**
* 完成一次建堆,最大值在堆的頂部(根節點)
*/
public
static
void
maxHeapify
(
int
[
] arrays
, int size
)
{
for
(int i
= size
-
1
; i
>=
0
; i
--
)
{
heapify
(arrays
, i
, size
)
;
}
}
/**
* 建堆
*
* @param arrays 看作是完全二叉樹
* @param currentRootNode 當前父節點位置
* @param size 節點總數
*/
public
static
void
heapify
(
int
[
] arrays
, int currentRootNode
, int size
)
{
if
(currentRootNode
< size
)
{
//左子樹和右字數的位置
int left
=
2
* currentRootNode
+
1
;
int right
=
2
* currentRootNode
+
2
;
//把當前父節點位置看成是最大的
int max
= currentRootNode
;
if
(left
< size
)
{
//如果比當前根元素要大,記錄它的位置
if
(arrays
[max
]
< arrays
[left
]
)
{
max
= left
;
}
}
if
(right
< size
)
{
//如果比當前根元素要大,記錄它的位置
if
(arrays
[max
]
< arrays
[right
]
)
{
max
= right
;
}
}
//如果最大的不是根元素位置,那麼就交換
if
(max
!= currentRootNode
)
{
int temp
= arrays
[max
]
;
arrays
[max
]
= arrays
[currentRootNode
]
;
arrays
[currentRootNode
]
= temp
;
//繼續比較,直到完成一次建堆
heapify
(arrays
, max
, size
)
;
}
}
}
2.7希爾排序
思路:
-
希爾排序實質上就是插入排序的增強版,希爾排序將陣列分隔成n組來進行插入排序,**直至該陣列巨集觀上有序,**最後再進行插入排序時就不用移動那麼多次位置了~
程式碼思路:
-
希爾增量一般是
gap = gap / 2
,只是比普通版插入排序多了這麼一個for迴圈罷了,難度並不大
/**
* 希爾排序
*
* @param arrays
*/
public
static
void
shellSort
(
int
[
] arrays
)
{
//增量每次都/2
for
(int step
= arrays
.length
/
2
; step
>
0
; step
/=
2
)
{
//從增量那組開始進行插入排序,直至完畢
for
(int i
= step
; i
< arrays
.length
; i
++
)
{
int j
= i
;
int temp
= arrays
[j
]
;
// j - step 就是代表與它同組隔壁的元素
while
(j
- step
>=
0
&& arrays
[j
- step
]
> temp
)
{
arrays
[j
]
= arrays
[j
- step
]
;
j
= j
- step
;
}
arrays
[j
]
= temp
;
}
}
}
2.8基數排序
思路:
-
基數排序(桶排序):將數字切割成個、十、百、千位放入到不同的桶子裡,放一次就按桶子順序回收一次,直至最大位數的數字放完~那麼該陣列就有序了
程式碼實現:
-
先找到陣列的最大值,然後根據最大值/10來作為迴圈的條件(只要>0,那麼就說明還有位數)
-
將個位、十位、...分配到桶子上,每分配一次就回收一次
public
static
void
main
(
String
[
] args
)
{
int
[
] arrays
=
{
6
,
4322
,
432
,
344
,
55
,
234
,
45
,
243
,
5
,
2
,
4
,
5
,
6
,
7
,
3245
,
345
,
345
,
234
,
68
,
65
}
;
radixSort
(arrays
)
;
System
.out
.
println
(
"Hello World"
+ arrays
)
;
}
public
static
void
radixSort
(
int
[
] arrays
)
{
//java學習交流:737251827 進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
int max
=
findMax
(arrays
,
0
, arrays
.length
-
1
)
;
//需要遍歷的次數由陣列最大值的位數來決定
for
(int i
=
1
; max
/ i
>
0
; i
= i
*
10
)
{
int
[
]
[
] buckets
=
new
int
[arrays
.length
]
[
10
]
;
//獲取每一位數字(個、十、百、千位...分配到桶子裡)
for
(int j
=
0
; j
< arrays
.length
; j
++
)
{
int num
=
(arrays
[j
]
/ i
)
%
10
;
//將其放入桶子裡
buckets
[j
]
[num
]
= arrays
[j
]
;
}
//回收桶子裡的元素
int k
=
0
;
//有10個桶子
for
(int j
=
0
; j
<
10
; j
++
)
{
//對每個桶子裡的元素進行回收
for
(int l
=
0
; l
< arrays
.length
; l
++
)
{
//如果桶子裡面有元素就回收(資料初始化會為0)
if
(buckets
[l
]
[j
]
!=
0
)
{
arrays
[k
++
]
= buckets
[l
]
[j
]
;
}
}
}
}
}
/**
* 遞迴,找出陣列最大的值
*
* @param arrays 陣列
* @param L 左邊界,第一個數
* @param R 右邊界,陣列的長度
* @return
*/
public
static int
findMax
(
int
[
] arrays
, int
L
, int
R
)
{
//如果該陣列只有一個數,那麼最大的就是該陣列第一個值了
if
(
L
==
R
)
{
return arrays
[
L
]
;
}
else
{
int a
= arrays
[
L
]
;
int b
=
findMax
(arrays
,
L
+
1
,
R
)
;
//找出整體的最大值
if
(a
> b
)
{
return a
;
}
else
{
return b
;
}
}
}
三、總結
對於排序的時間複雜度和穩定性網上的圖也很多很多,我就隨便找一張了(侵刪)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70010294/viewspace-2849313/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 氣泡排序的簡單理解排序
- 簡單易懂的氣泡排序排序
- javascript氣泡排序簡單介紹JavaScript排序
- 堆排序就這麼簡單排序
- 快速排序就這麼簡單排序
- 基數排序就這麼簡單排序
- 歸併排序就這麼簡單排序
- 插入排序就這麼簡單排序
- 選擇排序就這麼簡單排序
- 最簡單的氣泡排序還能怎麼優化?排序優化
- 用go實現簡單的氣泡排序Go排序
- 排序——氣泡排序排序
- std list/vector sort 排序就這麼簡單排序
- 氣泡排序排序
- 9. 氣泡排序,以及如何優化氣泡排序,氣泡排序屬於插入排序排序優化
- 排序之氣泡排序排序
- 排序:氣泡排序&快速排序排序
- js氣泡排序JS排序
- 氣泡排序-fusha排序
- 氣泡排序演示排序
- Shell氣泡排序排序
- d氣泡排序排序
- 氣泡排序正解排序
- JavaScript氣泡排序JavaScript排序
- java氣泡排序Java排序
- 氣泡排序 java排序Java
- php氣泡排序PHP排序
- Java 氣泡排序Java排序
- Javascript 氣泡排序JavaScript排序
- 氣泡排序(Java)排序Java
- 容器氣泡排序排序
- 氣泡排序1排序
- 氣泡排序法排序
- 基本排序之氣泡排序排序
- 排序:交換排序——氣泡排序法排序
- 漫畫:什麼是氣泡排序?排序
- 氣泡排序筆記排序筆記
- js氣泡排序動畫JS排序動畫