1. 冒泡排序
冒泡排序是一種簡單的排序算法。它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。
算法分析
比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最后一對。在這一點,最后的元素應該會是最大的數。針對所有的元素重復以上的步驟,除了最后一個。持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
原始待排序數組| 6 | 2 | 4 | 1 | 5 | 9 |
第一趟排序(外循環)
第一次兩兩比較6 > 2交換(內循環)
交換前狀態| 6 | 2 | 4 | 1 | 5 | 9 |
交換后狀態| 2 | 6 | 4 | 1 | 5 | 9 |
第二次兩兩比較,6 > 4交換
交換前狀態| 2 | 6 | 4 | 1 | 5 | 9 |
交換后狀態| 2 | 4 | 6 | 1 | 5 | 9 |
第三次兩兩比較,6 > 1交換
交換前狀態| 2 | 4 | 6 | 1 | 5 | 9 |
交換后狀態| 2 | 4 | 1 | 6 | 5 | 9 |
第四次兩兩比較,6 > 5交換
交換前狀態| 2 | 4 | 1 | 6 | 5 | 9 |
交換后狀態| 2 | 4 | 1 | 5 | 6 | 9 |
第五次兩兩比較,6 < 9不交換
交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |
交換后狀態| 2 | 4 | 1 | 5 | 6 | 9 |
第二趟排序(外循環)
第一次兩兩比較2 < 4不交換
交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |
交換后狀態| 2 | 4 | 1 | 5 | 6 | 9 |
第二次兩兩比較,4 > 1交換
交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |
交換后狀態| 2 | 1 | 4 | 5 | 6 | 9 |
第三次兩兩比較,4 < 5不交換
交換前狀態| 2 | 1 | 4 | 5 | 6 | 9 |
交換后狀態| 2 | 1 | 4 | 5 | 6 | 9 |
第四次兩兩比較,5 < 6不交換
交換前狀態| 2 | 1 | 4 | 5 | 6 | 9 |
交換后狀態| 2 | 1 | 4 | 5 | 6 | 9 |
第三趟排序(外循環)
第一次兩兩比較2 > 1交換
交換后狀態| 2 | 1 | 4 | 5 | 6 | 9 |
交換后狀態| 1 | 2 | 4 | 5 | 6 | 9 |
第二次兩兩比較,2 < 4不交換
交換后狀態| 1 | 2 | 4 | 5 | 6 | 9 |
交換后狀態| 1 | 2 | 4 | 5 | 6 | 9 |
第三次兩兩比較,4 < 5不交換
交換后狀態| 1 | 2 | 4 | 5 | 6 | 9 |
交換后狀態| 1 | 2 | 4 | 5 | 6 | 9 |
第四趟排序(外循環)無交換
第五趟排序(外循環)無交換
排序完畢,輸出最終結果1 2 4 5 6 9
- (NSMutableArray *)bubbleSortArray:(NSMutableArray *)arr
{
id temp;
int i, j;
for (i=0; i < [arr count] - 1; ++i) {
for (j=0; j < [arr count] - i - 1; ++j) {
if (arr[j] > arr[j+1]) { // 升序排列
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
2.插入排序
插入排序就是每一步都將一個待排數據按其大小插入到已經排序的數據中的適當位置,直到全部插入完畢。 插入排序方法分直接插入排序和折半插入排序兩種。
時間復雜度與空間復雜度
時間復雜度:O(n^2)
空間復雜度:O(1)
最少比較次數:(已排序的數組)n-1次
最多比較次數:(降序的數組)n(n-1)/2次
數組在已排序或者是“近似排序”時,插入排序效率的最好情況運行時間為O(n);插入排序最壞情況運行時間和平均情況運行時間都為O(n^2) 。
插入排序不適合對大量數據排序,適合對接近排序的數據排序。插入排序是穩定排序。通常,插入排序呈現出二次排序算法中的最佳性能。對于具有較少元素(如n<=15)的列表來說,二次算法十分有效。在列表已被排序時,插入排序是線性算法O(n)。在列表“近似排序”時,插入排序仍然是線性算法。在列表的許多元素已位于正確的位置上時,就會出現“近似排序”的條件。
算法描述
假定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)為真,因此,這個元素會占用新排序子列表的第一個位置。在掃描期間,大于目標值target的每個元素都會向右滑動一個位置(arr[j]=arr[j-1])。一旦確定了正確位置j,目標值target(即原始的arr[i])就會被復制到這個位置。與選擇排序不同的是,插入排序將數據向右滑動,并且不會執行交換
- (NSMutableArray *)insertSortArray:(NSMutableArray *)dataArr
{
for (int i = 0; i < dataArr.count; i++) {
for (int j = i; j > 0; j--) {
if ([dataArr[j] intValue] < [dataArr[j - 1] intValue]) {
[dataArr exchangeObjectAtIndex:j withObjectAtIndex:j-1];
}
}
}
return dataArr;
}
3.快速排序
快速排序(Quicksort)是對冒泡排序的一種改進。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然后再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。在平均狀況下,排序 n 個項目要Ο(n log n)次比較。在最壞狀況下則需要Ο(n2)次比較,但這種狀況并不常見。快速排序使用分治法(Divide and conquer)策略來把一個串行(list)分為兩個子串行(sub-lists)。
算法步驟:
從數列中挑出一個元素,稱為 “基準”(pivot),重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的后面(相同的數可以到任一邊)。在這個分區退出之后,該基準就處于數列的中間位置。這個稱為分區(partition)操作。遞歸地(recursive)把小于基準值元素的子數列和大于基準值元素的子數列排序。遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個算法總會退出,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最后的位置去。
一趟快速排序的算法
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素作為關鍵數據,賦值給key,即key=A[0];
3)從j開始向前搜索,即由后開始向前搜索(j--),找到第一個小于key的值A[j],將A[j]和A[i]互換;
4)從i開始向后搜索,即由前開始向后搜索(i++),找到第一個大于key的A[i],將A[i]和A[j]互換;
5)重復第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小于key,4中A[i]不大于key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)
- (void)quickSortWithArray:(NSMutableArray *)array withLeft:(NSInteger)left andRight:(NSInteger)right{
if (left >= right) return;
NSInteger i = left;
NSInteger j = right;
NSInteger key = [array[left] integerValue];
while (i < j) {
while (i < j && key <= [array[j] integerValue]) {
j--;
}
array[i] = array[j];
while (i < j && key >= [array[i] integerValue]) {
i++;
}
array[j] = array[i];
}
array[i] = [NSNumber numberWithInteger:key];
[self quickSortWithArray:array withLeft:left andRight:i - 1];
[self quickSortWithArray:array withLeft:i + 1 andRight:right];
}
以上算法的調用示范
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *dataArr = [NSMutableArray arrayWithObjects:@3,@6,@4,@1,@7,@3,@9,@5, nil];
// NSMutableArray *bubbleArray = [self bubbleSortArray:dataArr];
// NSLog(@"冒泡排序 %@ \n",bubbleArray);
//
// NSMutableArray *insertArray = [self insertSortArray:dataArr];
// NSLog(@"插入排序 %@ \n",insertArray);
//
// NSMutableArray *selectArray = [self selectSortArray:dataArr];
// NSLog(@"選擇排序 %@ \n",selectArray);
//
// [self quickSortWithArray:dataArr withLeft:0 andRight:dataArr.count -1];
// NSLog(@"快速排序 %@ \n",dataArr);
}