看漫畫學java:什麼是雞尾酒排序?

在上一篇漫畫中,小灰介紹了冒泡排序的思路和幾種變化:

漫畫:什麼是冒泡排序?

那麼,雞尾酒排序又是何方神聖呢?我們這一期將會詳細講述。

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

讓我們首先來回顧一下冒泡排序的思想:

冒泡排序的每一個元素都可以像小氣泡一樣,根據自身大小,一點一點向著數組的一側移動。算法的每一輪從都是從左到右比較元素,進行單向的位置交換

那麼雞尾酒排序做了怎樣的優化呢?

雞尾酒排序的元素比較和交換過程是雙向的。

讓我們來舉一個栗子:

看漫畫學java:什麼是雞尾酒排序?

有8個數組成一個無序數列:2,3,4,5,6,7,8,1,希望從小到大排序。

如果按照冒泡排序的思想,排序的過程是什麼樣呢?

第一輪結果(8和1交換)

看漫畫學java:什麼是雞尾酒排序?

第二輪結果(7和1交換)

看漫畫學java:什麼是雞尾酒排序?

第三輪結果(6和1交換)

看漫畫學java:什麼是雞尾酒排序?

第四輪結果(5和1交換)

看漫畫學java:什麼是雞尾酒排序?

第五輪結果(4和1交換)

看漫畫學java:什麼是雞尾酒排序?

第六輪結果(3和1交換)

看漫畫學java:什麼是雞尾酒排序?

第七輪結果(2和1交換)

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

雞尾酒排序是什麼樣子呢?讓我們來看一看詳細過程:

第一輪(和冒泡排序一樣,8和1交換)

看漫畫學java:什麼是雞尾酒排序?

第二輪

此時開始不一樣了,我們反過來從右往左

比較和交換:

8已經處於有序區,我們忽略掉8,讓1和7比較。元素1小於7,所以1和7交換位置:

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

接下來1和6比較,元素1小於6,所以1和6交換位置:

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

接下來1和5比較,元素1小於5,所以1和5交換位置:

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

接下來1和4交換,1和3交換,1和2交換,最終成為了下面的結果:

看漫畫學java:什麼是雞尾酒排序?

第三輪(雖然已經有序,但是流程並沒有結束)

雞尾酒排序的第三輪,需要重新從左向右比較和交換:

1和2比較,位置不變;2和3比較,位置不變;3和4比較,位置不變......6和7比較,位置不變。

沒有元素位置交換,證明已經有序,排序結束。

這就是雞尾酒排序的思路。排序過程就像鐘擺一樣,第一輪從左到右,第二輪從右到左,第三輪再從左到右......

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

public class CockTailSort {

  1. private
  2. static
  3. void
  4. sort(
  5. int
  6. array[])
  7. {
  8. int tmp = 0;
  9. for
  10. (
  11. int
  12. i=
  13. 0
  14. ; i
  15. 2
  16. -1; i++)
  17. {
  18. //有序標記,每一輪的初始是true
  19. boolean
  20. isSorted =
  21. true
  22. ;
  23. //奇數輪,從左向右比較和交換
  24. for
  25. (
  26. int
  27. j=i; j
  28. ; j++)
  29. {
  30. if
  31. (array[j] > array[j+
  32. 1
  33. ])
  34. {
  35. tmp = array[j];
  36. array[j] = array[j+
  37. 1
  38. ];
  39. array[j+
  40. 1
  41. ] = tmp;
  42. //有元素交換,所以不是有序,標記變為false
  43. isSorted =
  44. false
  45. ;
  46. }
  47. }
  48. if
  49. (isSorted){
  50. break
  51. ;
  52. }
  53. //偶數輪,從右向左比較和交換
  54. for
  55. (
  56. int
  57. j=array.length-i-
  58. 1
  59. ; j>i; j--)
  60. {
  61. if
  62. (array[j] < array[j-
  63. 1
  64. ])
  65. {
  66. tmp = array[j];
  67. array[j] = array[j-
  68. 1
  69. ];
  70. array[j-
  71. 1
  72. ] = tmp;
  73. //有元素交換,所以不是有序,標記變為false
  74. isSorted =
  75. false
  76. ;
  77. }
  78. }
  79. if
  80. (isSorted){
  81. break
  82. ;
  83. }
  84. }
  85. }
  86. public
  87. static
  88. void
  89. main(
  90. String
  91. [] args){
  92. int
  93. [] array =
  94. new
  95. int
  96. []{
  97. 2
  98. ,
  99. 3
  100. ,
  101. 4
  102. ,
  103. 5
  104. ,
  105. 6
  106. ,
  107. 7
  108. ,
  109. 8
  110. ,
  111. 1
  112. };
  113. sort(array);
  114. System
  115. .
  116. out
  117. .println(
  118. Arrays
  119. .toString(array));
  120. }

}

這段代碼是雞尾酒排序的原始實現。代碼外層的大循環控制著所有排序回合,大循環內包含兩個小循環,第一個循環從左向右比較並交換元素,第二個循環從右向左比較並交換元素。

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

讓我們來回顧一下冒牌排序針對有序區的優化思路:

原始的冒泡排序,有序區的長度和排序的輪數是相等的。比如第一輪排序過後的有序區長度是1,第二輪排序過後的有序區長度是2 ......

要想優化,我們可以在每一輪排序的最後,記錄下最後一次元素交換的位置,那個位置也就是無序數列的邊界,再往後就是有序區了。

對於單向的冒泡排序,我們需要設置一個邊界值,對於雙向的雞尾酒排序,我們需要設置兩個邊界值。請看代碼:

public class CockTailSort {

  1. private
  2. static
  3. void
  4. sort
  5. (
  6. int
  7. array
  8. [])
  9. {
  10. int
  11. tmp
  12. =
  13. 0
  14. ;
  15. //記錄右側最後一次交換的位置
  16. int
  17. lastRightExchangeIndex
  18. =
  19. 0
  20. ;
  21. //記錄左側最後一次交換的位置
  22. int
  23. lastLeftExchangeIndex
  24. =
  25. 0
  26. ;
  27. //無序數列的右邊界,每次比較只需要比到這裡為止
  28. int
  29. rightSortBorder
  30. =
  31. array
  32. .
  33. length
  34. -
  35. 1
  36. ;
  37. //無序數列的左邊界,每次比較只需要比到這裡為止
  38. int
  39. leftSortBorder
  40. =
  41. 0
  42. ;
  43. for
  44. (
  45. int
  46. i
  47. =
  48. 0
  49. ;
  50. i
  51. <
  52. array
  53. .
  54. length
  55. /
  56. 2
  57. ;
  58. i
  59. ++)
  60. {
  61. //有序標記,每一輪的初始是true
  62. boolean
  63. isSorted
  64. =
  65. true
  66. ;
  67. //奇數輪,從左向右比較和交換
  68. for
  69. (
  70. int
  71. j
  72. =
  73. leftSortBorder
  74. ;
  75. j
  76. <
  77. rightSortBorder
  78. ;
  79. j
  80. ++)
  81. {
  82. if
  83. (
  84. array
  85. [
  86. j
  87. ]
  88. >
  89. array
  90. [
  91. j
  92. +
  93. 1
  94. ])
  95. {
  96. tmp
  97. =
  98. array
  99. [
  100. j
  101. ];
  102. array
  103. [
  104. j
  105. ]
  106. =
  107. array
  108. [
  109. j
  110. +
  111. 1
  112. ];
  113. array
  114. [
  115. j
  116. +
  117. 1
  118. ]
  119. =
  120. tmp
  121. ;
  122. //有元素交換,所以不是有序,標記變為false
  123. isSorted
  124. =
  125. false
  126. ;
  127. lastRightExchangeIndex
  128. =
  129. j
  130. ;
  131. }
  132. }
  133. rightSortBorder
  134. =
  135. lastRightExchangeIndex
  136. ;
  137. if
  138. (
  139. isSorted
  140. ){
  141. break
  142. ;
  143. }
  144. //偶數輪,從右向左比較和交換
  145. for
  146. (
  147. int
  148. j
  149. =
  150. rightSortBorder
  151. ;
  152. j
  153. >
  154. leftSortBorder
  155. ;
  156. j
  157. --)
  158. {
  159. if
  160. (
  161. array
  162. [
  163. j
  164. ]
  165. <
  166. array
  167. [
  168. j
  169. -
  170. 1
  171. ])
  172. {
  173. tmp
  174. =
  175. array
  176. [
  177. j
  178. ];
  179. array
  180. [
  181. j
  182. ]
  183. =
  184. array
  185. [
  186. j
  187. -
  188. 1
  189. ];
  190. array
  191. [
  192. j
  193. -
  194. 1
  195. ]
  196. =
  197. tmp
  198. ;
  199. //有元素交換,所以不是有序,標記變為false
  200. isSorted
  201. =
  202. false
  203. ;
  204. lastLeftExchangeIndex
  205. =
  206. j
  207. ;
  208. }
  209. }
  210. leftSortBorder
  211. =
  212. lastLeftExchangeIndex
  213. ;
  214. if
  215. (
  216. isSorted
  217. ){
  218. break
  219. ;
  220. }
  221. }
  222. }
  223. public
  224. static
  225. void
  226. main
  227. (
  228. String
  229. []
  230. args
  231. ){
  232. int
  233. []
  234. array
  235. =
  236. new
  237. int
  238. []{
  239. 2
  240. ,
  241. 3
  242. ,
  243. 4
  244. ,
  245. 5
  246. ,
  247. 6
  248. ,
  249. 7
  250. ,
  251. 8
  252. ,
  253. 1
  254. };
  255. sort
  256. (
  257. array
  258. );
  259. System
  260. .
  261. out
  262. .
  263. println
  264. (
  265. Arrays
  266. .
  267. toString
  268. (
  269. array
  270. ));
  271. }

}

代碼中使用了左右兩個邊界值,rightSortBorder 代表右邊界,leftSortBorder代表左邊界。

在比較和交換元素時,奇數輪從 leftSortBorder 遍歷到 rightSortBorder 位置,偶數輪從 rightSortBorder 遍歷到 leftSortBorder 位置。

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

看漫畫學java:什麼是雞尾酒排序?

—————END—————


分享到:


相關文章: