本篇文章主要介紹的是Java和Android開發中常見的排序概念,由于篇幅的問題我将其分成了幾篇。主要有基礎篇和實戰篇。本篇主要學習的是基礎排序的内容,主要學習以下四種基礎排序:冒泡排序、選擇排序、插入排序。
冒泡排序:
對于冒泡排序,我們不是很陌生,因為這種排序很基礎且面試出現的頻率比較大。 對于冒泡排序比較好的了解是
:對比數組内相鄰的兩個元素,如果 元素值 [i] 大于 [i+1] 那麼,這兩個元素就需要交換位置......直到數組最後一個索引對應的元素值最大。
根據上面的描述,我們可以思考,如果數組元素值 [i] 大于 [i+1] 才去交換位置,那麼交換位置以後我們需要将其屬性值給記錄下來,常見的做法是
使用第三方來記錄變化的值首先,我們定義一個數組,然後根據上面的描述,不斷去判斷數組内兩個相鄰的屬性值,然後通過臨時變量去記錄,于是,就有了下面的參考代碼:
參考僞代碼 - 1
通過這樣一遍操作以後,數組内的最大值就已經在最後的索引位置了,但這樣達不到我們對數組進行整體排序的要求。是以還要對數組進行繼續判斷,由于上面的一次排序已經将最大值給找出來了,是以最後一個索引對應的值我們就不需要在對其進行排序了,是以第二次排序有以下的參考思路代碼:
參考僞代碼 - 2
關于以上參考代碼的思考:
如果
我們的數組有4個屬性值:那麼第一趟需要比較3
次,分别是 [0] [1] 、 [1] [2] 、 [2] [3] 這一趟排序比較出來的最大值:[3]第二趟需要比較2
次 ,分别是 [0] [1] 、 [1] [2] 這一趟排序比較出來的較大值:[2]第三趟需要比較1
次,也就是 [0] [1] 這一趟排序比較出來的較大值:[1] 是以,通過以上試驗步驟可以了解這種排序的比較趟數規律以及每一趟需要比較的次數,是以就可以通過循環去操作,下面是冒泡排序比較熟悉的寫法冒泡排序
冒泡排序優化:試想有下面這樣一個數組:
int arr[ ] = { 1,2,3,4,6,5 } ;根據對這個數組的直覺判斷,我們隻需周遊判斷一趟就可以将數組進行整體排序,但是上面的寫法對于這種情況下的數組就會顯得有些備援(判斷5趟,每一趟依次遞減)。那有沒有比較好的方案去優化這種情況?答案是有的,我們可以定義一個TAG,來判斷是否發生變化。我們知道發生位置變化的時機是在内層循環裡面進行操作的,是以我們可以這樣操作:
冒泡排序優化
關于冒泡排序的内容基本上就介紹到這裡。
選擇排序:
選擇排序對Java開發來說也不是那麼陌生,因為Java内置了API友善我們快速調用,那麼關于選擇排序的解釋是(來自百度百科):選擇排序(Selection sort)是一種簡單直覺的排序算法。它的工作原理是
每一次從待排序的資料元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的資料元素排完。
選擇排序是不穩定的排序方法(比如序列[5, 5, 3]第一次就将第一個[5]與[3]交換,導緻第一個5挪動到第二個5後面)。基于此思想的算法主要有簡單選擇排序、樹型選擇排序和堆排序。(這裡隻介紹常用的簡單選擇排序)。
簡單選擇排序的基本思想:給定數組:int[] arr={裡面n個資料};第1趟排序,在待排序資料arr[1]~arr[n]中選出最小的資料,将它與arrr[1]交換;第2趟,在待排序資料arr[2]~arr[n]中選出最小的資料,将它與r[2]交換;以此類推,第i趟在待排序資料arr[i]~arr[n]中選出最小的資料,将它與r[i]交換,直到全部排序完成。
舉例:首先定義一個數組
int [ ] arr = { 5,2,8,4,9,1 } ;那麼根據上面的定義,選擇排序的邏輯就應該按照以下步驟去執行:
第一趟排序: 原始資料:5 2 8 4 9 1 最小資料1,把1放在首位,也就是1和5互換位置,排序結果:1 2 8 4 9 5
第二趟排序:第1以外的資料{ 2 8 4 9 5 }進行比較,2最小。排序結果:1 2 8 4 9 5
第三趟排序:除1、2以外的資料{ 8 4 9 5 }進行比較,4最小,8和4交換。排序結果:1 2 4 8 9 5
第四趟排序:除第1、2、4以外的其他資料{8 9 5}進行比較,5最小,8和5交換。排序結果:1 2 4 5 9 8
第五趟排序:除第1、2、4、5以外的其他資料{9 8}進行比較,8最小,8和9交換。排序結果:1 2 4 5 8 9
通過以上試驗步驟有以下結論:
A:一個數組是需要n-1趟排序的(因為直到剩下一個元素時,才不需要找最大值)
B:每交換1次,再次找最大值時就将範圍縮小1
C:查詢目前趟數最大值實際不用知道具體的屬性值是多少,也就是我們隻需
知道其索引即可,交換也可以根據角标來進行交換
根據以上結論結合循環的使用,我們可以有以下選擇排序的代碼:
選擇排序
在上面關于選擇排序的概念提到,這是一種不穩定的排序方法,那麼什麼叫排序的穩定性?為了更好的了解這一概念,首先看下這個數組
int [ ] arr = { 6,6,2 } ;排序的穩定性是指:排序前2個相等的數在序列的前後位置順序和排序後它們兩個的前後位置順序相同,如果相同,則是穩定的排序方法;如果不相同,則是不穩定的排序方法。假定我們使用選擇排序的話,那第一趟排序後結果就是[2,6,6]。因為這個數組在定義之初就有兩個相同的值,屬性值對應的索引分别是array [0] 和array [1],結果經過排序,array[0]的跑到了array[2]上了。
那麼這導緻了:
2個相等的數其在序列的前後位置順序和排序後它們兩個的前後位置順序不相同,是以,我們就說它是不穩定的
再回到上面的問題,為什麼冒泡排序是穩定的,主要原因是:冒泡排序進行
倆倆比較的時候,沒有對相等的資料進行交換(因為沒必要)。是以它不存在2個相等的數其在序列的前後位置順序和排序後它們兩個的前後位置順序不相同。
那麼穩定排序的好處是什麼?一種說法如下:如果我們隻對一串數字排序,那麼穩定與否确實不重要,因為一串數字的屬性是單一的,就是數字值的大小。但是排序的元素往往不隻有一個屬性,例如我們對一群人按年齡排序,但是人除了年齡屬性還有身高體重屬性,在年齡相同時如果不想破壞原先身高體重的次序,就必須用穩定排序算法。
關于選擇排序和排序的穩定性的内容基本上就介紹到這裡。
插入排序:
什麼是插入排序?插入排序的基本操作就是
将一個資料插入到已經排好序的有序資料中,進而得到一個新的、個數加一的有序資料,算法适用于少量資料的排序。插入排序是一種穩定的排序方法。那麼如何更好的去了解插入排序?玩過鬥地主的小夥伴都知道,我們起手第一張手牌以後,然後抽到第二張牌一般都會放到第一張手牌的左邊或者右邊,類似下圖:
插入排序
插入排序就是借用了這種思想,先給定一個排好序的序列(通常設定為
給定要排序序列的第一個值),然後陸續将後面的值與前面排好序的比較,如果是小于前面的值,就插到前面去。就這樣一直比較,然後最後總會插入到合适的位置,當然啦,如果是插入到第一位了,也算完成了插入。
插入排序執行流程如下:
現在假設有一個數組,n是數組的長度。
首先假設第一個元素被放置在正确的位置上,這樣僅需從1 —— n-1 範圍内對剩餘元素進行排序。對于每次周遊,從0 —— i-1 範圍内的元素已經被排好序。每次周遊的任務是:通過掃描前面已排序的子清單,将位置 i 處的元素定位到從0 到 i 的子清單之内的正确的位置上。
我們可以 arr[ i ] 指派給名為target的臨時元素。向下掃描清單,比較這個目标值target 與 arr[ i-1 ]、arr[i-2]的大小,依次類推。這個比較過程在小于或等于目标值的第一個元素( arr[ j ] )處停止,或者在清單開始處停止(j = 0)。
如果出現arr[ i ]小于前面任何已排序元素時,後一個條件(j = 0)為true,是以,這個元素會占用新排序子清單的第一個位置。在掃描期間,大于目标值target的每個元素都會向右滑動一個位置(arr[ j ] = arr[ j-1 ])。一旦确定了正确位置 j,目标值target(即原始的arr [ i ])就會被複制到這個位置。
與選擇排序不同的是,插入排序将資料向右滑動,并且不會執行交換。
有了上面的流程,可以有以下的代碼:
本篇文章主要學習的是基礎排序中的冒泡排序、選擇排序、插入排序,下一篇學習快速排序、歸并排序。
如果這篇文章對你有幫助,希望各位看官留下寶貴的star,謝謝。
Ps:著作權歸作者所有,轉載請注明作者, 商業轉載請聯系作者獲得授權,非商業轉載請注明出處(開頭或結尾請添加轉載出處,添加原文url位址),文章請勿濫用,也希望大家尊重筆者的勞動成果。