A. 常見的排序演算法—選擇,冒泡,插入,快速,歸並
太久沒看代碼了,最近打算復習一下java,又突然想到了排序演算法,就把幾種常見的排序演算法用java敲了一遍,這里統一將無序的序列從小到大排列。
選擇排序是一種簡單直觀的排序演算法。它的工作原理是:第一次從待排序的數據元素中選出最小的一個元素,存放在序列的起始位置,然後再從剩餘的未排序元素中尋找到最小元素,繼續放在下一個位置,直到待排序元素個數為0。
選擇排序代碼如下:
public void Select_sort(int[] arr) {
int temp,index;
for( int i=0;i<10;i++) {
index = i;
for(int j = i + 1 ; j < 10 ; j++) {
if(arr[j] < arr[index])
index = j;
}
/*
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
*/
swap(arr,i,index);
}
System.out.print("經過選擇排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr[i] +" ");
System.out.println("");
}
冒泡排序是一種比較基礎的排序演算法,其思想是相鄰的元素兩兩比較,較大的元素放後面,較小的元素放前面,這樣一次循環下來,最大元素就會歸位,若數組中元素個數為n,則經過(n-1)次後,所有元素就依次從小到大排好序了。整個過程如同氣泡冒起,因此被稱作冒泡排序。
選擇排序代碼如下:
public void Bubble_sort(int[] arr) {
int temp;
for(int i = 0 ; i < 9 ; i++) {
for(int j = 0 ; j < 10 - i - 1 ;j++) {
if(arr[j] > arr[j+1]) {
/*
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
*/
swap(arr,j,j+1);
}
}
}
System.out.print("經過冒泡排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr[i] +" ");
System.out.println("");
}
插入排序也是一種常見的排序演算法,插入排序的思想是:創建一個與待排序數組等大的數組,每次取出一個待排序數組中的元素,然後將其插入到新數組中合適的位置,使新數組中的元素保持從小到大的順序。
插入排序代碼如下:
public void Insert_sort(int[] arr) {
int length = arr.length;
int[] arr_sort = new int[length];
int count = 0;
for(int i = 0;i < length; i++) {
if(count == 0) {
arr_sort[0] = arr[0];
}else if(arr[i] >= arr_sort[count - 1]) {
arr_sort[count] = arr[i];
}else if(arr[i] < arr_sort[0]) {
insert(arr,arr_sort,arr[i],0,count);
}else {
for(int j = 0;j < count - 1; j++) {
if(arr[i] >= arr_sort[j] && arr[i] < arr_sort[j+1]) {
insert(arr,arr_sort,arr[i],j+1,count);
break;
}
}
}
count++;
}
System.out.print("經過插入排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr_sort[i] +" ");
System.out.println("");
}
public void insert(int[] arr,int[] arr_sort,int value,int index,int count) {
for(int i = count; i > index; i--)
arr_sort[i] = arr_sort[i-1];
arr_sort[index] = value;
}
快速排序的效率比冒泡排序演算法有大幅提升。因為使用冒泡排序時,一次外循環只能歸位一個值,有n個元素最多就要執行(n-1)次外循環。而使用快速排序時,一次可以將所有元素按大小分成兩堆,也就是平均情況下需要logn輪就可以完成排序。
快速排序的思想是:每趟排序時選出一個基準值(這里以首元素為基準值),然後將所有元素與該基準值比較,並按大小分成左右兩堆,然後遞歸執行該過程,直到所有元素都完成排序。
public void Quick_sort(int[] arr, int left, int right) {
if(left >= right)
return ;
int temp,t;
int j = right;
int i = left;
temp = arr[left];
while(i < j) {
while(arr[j] >= temp && i < j)
j--;
while(arr[i] <= temp && i < j)
i++;
if(i < j) {
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[left] = arr[i];
arr[i] = temp;
Quick_sort(arr,left, i - 1);
Quick_sort(arr, i + 1, right);
}
歸並排序是建立在歸並操作上的一種有效的排序演算法,歸並排序對序列的元素進行逐層折半分組,然後從最小分組開始比較排序,每兩個小分組合並成一個大的分組,逐層進行,最終所有的元素都是有序的。
public void Mergesort(int[] arr,int left,int right) {
if(right - left > 0) {
int[] arr_1 = new int[(right - left)/2 + 1];
int[] arr_2 = new int[(right - left + 1)/2];
int j = 0;
int k = 0;
for(int i = left;i <= right;i++) {
if(i <= (right + left)/2) {
arr_1[j++] = arr[i];
}else {
arr_2[k++] = arr[i];
}
}
Mergesort(arr_1,0,(right - left)/2);
Mergesort(arr_2,0,(right - left - 1)/2);
Merge(arr_1,arr_2,arr);
}
}
public void Merge(int[] arr_1,int[] arr_2,int[] arr) {
int i = 0;
int j = 0;
int k = 0;
int L1 = arr_1.length;
int L2 = arr_2.length;
while(i < L1 && j < L2) {
if(arr_1[i] <= arr_2[j]) {
arr[k] = arr_1[i];
i++;
}else {
arr[k] = arr_2[j];
j++;
}
k++;
}
if(i == L1) {
for(int t = j;j < L2;j++)
arr[k++] = arr_2[j];
}else {
for(int t = i;i < L1;i++)
arr[k++] = arr_1[i];
}
}
歸並排序這里我使用了left,right等變數,使其可以通用,並沒有直接用數字表示那麼明確,所以給出相關偽代碼,便於理解。
Mergesort(arr[0...n-1])
//輸入:一個可排序數組arr[0...n-1]
//輸出:非降序排列的數組arr[0...n-1]
if n>1
arr[0...n/2-1] to arr_1[0...(n+1)/2-1]//確保arr_1中元素個數>=arr_2中元素個數
//對於總個數為奇數時,arr_1比arr_2中元素多一個;對於總個數為偶數時,沒有影響
arr[n/2...n-1] to arr_2[0...n/2-1]
Mergesort(arr_1[0...(n+1)/2-1])
Mergesort(arr_2[0...n/2-1])
Merge(arr_1,arr_2,arr)
Merge(arr_1[0...p-1],arr_2[0...q-1],arr[0...p+q-1])
//輸入:兩個有序數組arr_1[0...p-1]和arr_2[0...q-1]
//輸出:將arr_1與arr_2兩數組合並到arr
int i<-0;j<-0;k<-0
while i
<p span="" do<="" jif arr_1[i] <= arr_2[j]
arr[k] <- arr_1[i]
i<-i+1
else arr[k] <- arr_2[j];j<-j+1
k<-k+1
if i=p
arr_2[j...q-1] to arr[k...p+q-1]
else arr_1[i...p-1] to arr[k...p+q-1]
package test_1;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] arr_1 = new int[10];
for(int i = 0 ; i < 10 ; i++)
arr_1[i] = sc.nextInt();
Sort demo_1 = new Sort();
//1~5一次只能運行一個,若多個同時運行,則只有第一個有效,後面幾個是無效排序。因為第一個運行的已經將帶排序數組排好序。
demo_1.Select_sort(arr_1);//-----------------------1
//demo_1.Bubble_sort(arr_1);//---------------------2
/* //---------------------3
demo_1.Quick_sort(arr_1, 0 , arr_1.length - 1);
System.out.print("經過快速排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr_1[i] +" ");
System.out.println("");
*/
//demo_1.Insert_sort(arr_1);//--------------------4
/* //--------------------5
demo_1.Mergesort(arr_1,0,arr_1.length - 1);
System.out.print("經過歸並排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr_1[i] +" ");
System.out.println("");
*/
}
}
class Sort {
public void swap(int arr[],int a, int b) {
int t;
t = arr[a];
arr[a] = arr[b];
arr[b] = t;
}
public void Select_sort(int[] arr) {
int temp,index;
for( int i=0;i<10;i++) {
index = i;
for(int j = i + 1 ; j < 10 ; j++) {
if(arr[j] < arr[index])
index = j;
}
/*
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
*/
swap(arr,i,index);
}
System.out.print("經過選擇排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr[i] +" ");
System.out.println("");
}
public void Bubble_sort(int[] arr) {
int temp;
for(int i = 0 ; i < 9 ; i++) {
for(int j = 0 ; j < 10 - i - 1 ;j++) {
if(arr[j] > arr[j+1]) {
/*
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
*/
swap(arr,j,j+1);
}
}
}
System.out.print("經過冒泡排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr[i] +" ");
System.out.println("");
}
public void Quick_sort(int[] arr, int left, int right) {
if(left >= right)
return ;
int temp,t;
int j = right;
int i = left;
temp = arr[left];
while(i < j) {
while(arr[j] >= temp && i < j)
j--;
while(arr[i] <= temp && i < j)
i++;
if(i < j) {
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[left] = arr[i];
arr[i] = temp;
Quick_sort(arr,left, i - 1);
Quick_sort(arr, i + 1, right);
}
public void Insert_sort(int[] arr) {
int length = arr.length;
int[] arr_sort = new int[length];
int count = 0;
for(int i = 0;i < length; i++) {
if(count == 0) {
arr_sort[0] = arr[0];
}else if(arr[i] >= arr_sort[count - 1]) {
arr_sort[count] = arr[i];
}else if(arr[i] < arr_sort[0]) {
insert(arr,arr_sort,arr[i],0,count);
}else {
for(int j = 0;j < count - 1; j++) {
if(arr[i] >= arr_sort[j] && arr[i] < arr_sort[j+1]) {
insert(arr,arr_sort,arr[i],j+1,count);
break;
}
}
}
count++;
}
System.out.print("經過插入排序後:");
for(int i = 0 ; i < 10 ; i++)
System.out.print( arr_sort[i] +" ");
System.out.println("");
}
public void insert(int[] arr,int[] arr_sort,int value,int index,int count) {
for(int i = count; i > index; i--)
arr_sort[i] = arr_sort[i-1];
arr_sort[index] = value;
}
public void Mergesort(int[] arr,int left,int right) {
if(right - left > 0) {
int[] arr_1 = new int[(right - left)/2 + 1];
int[] arr_2 = new int[(right - left + 1)/2];
int j = 0;
int k = 0;
for(int i = left;i <= right;i++) {
if(i <= (right + left)/2) {
arr_1[j++] = arr[i];
}else {
arr_2[k++] = arr[i];
}
}
Mergesort(arr_1,0,(right - left)/2);
Mergesort(arr_2,0,(right - left - 1)/2);
Merge(arr_1,arr_2,arr);
}
}
public void Merge(int[] arr_1,int[] arr_2,int[] arr) {
int i = 0;
int j = 0;
int k = 0;
int L1 = arr_1.length;
int L2 = arr_2.length;
while(i < L1 && j < L2) {
if(arr_1[i] <= arr_2[j]) {
arr[k] = arr_1[i];
i++;
}else {
arr[k] = arr_2[j];
j++;
}
k++;
}
if(i == L1) {
for(int t = j;j < L2;j++)
arr[k++] = arr_2[j];
}else {
for(int t = i;i < L1;i++)
arr[k++] = arr_1[i];
}
}
}
若有錯誤,麻煩指正,不勝感激。
B. 排序演算法有多少種
排序(Sorting) 是計算機程序設計中的一種重要操作,它的功能是將一個數據元素(或記錄)的任意序列,重新排列成一個關鍵字有序的序列。
排序就是把集合中的元素按照一定的次序排序在一起。一般來說有升序排列和降序排列2種排序,在演算法中有8中基本排序:
(1)冒泡排序;
(2)選擇排序;
(3)插入排序;
(4)希爾排序;
(5)歸並排序;
(6)快速排序;
(7)基數排序;
(8)堆排序;
(9)計數排序;
(10)桶排序。
插入排序
插入排序演算法是基於某序列已經有序排列的情況下,通過一次插入一個元素的方式按照原有排序方式增加元素。這種比較是從該有序序列的最末端開始執行,即要插入序列中的元素最先和有序序列中最大的元素比較,若其大於該最大元素,則可直接插入最大元素的後面即可,否則再向前一位比較查找直至找到應該插入的位置為止。插入排序的基本思想是,每次將1個待排序的記錄按其關鍵字大小插入到前面已經排好序的子序列中,尋找最適當的位置,直至全部記錄插入完畢。執行過程中,若遇到和插入元素相等的位置,則將要插人的元素放在該相等元素的後面,因此插入該元素後並未改變原序列的前後順序。我們認為插入排序也是一種穩定的排序方法。插入排序分直接插入排序、折半插入排序和希爾排序3類。
冒泡排序
冒泡排序演算法是把較小的元素往前調或者把較大的元素往後調。這種方法主要是通過對相鄰兩個元素進行大小的比較,根據比較結果和演算法規則對該二元素的位置進行交換,這樣逐個依次進行比較和交換,就能達到排序目的。冒泡排序的基本思想是,首先將第1個和第2個記錄的關鍵字比較大小,如果是逆序的,就將這兩個記錄進行交換,再對第2個和第3個記錄的關鍵字進行比較,依次類推,重復進行上述計算,直至完成第(n一1)個和第n個記錄的關鍵字之間的比較,此後,再按照上述過程進行第2次、第3次排序,直至整個序列有序為止。排序過程中要特別注意的是,當相鄰兩個元素大小一致時,這一步操作就不需要交換位置,因此也說明冒泡排序是一種嚴格的穩定排序演算法,它不改變序列中相同元素之間的相對位置關系。
選擇排序
選擇排序演算法的基本思路是為每一個位置選擇當前最小的元素。選擇排序的基本思想是,基於直接選擇排序和堆排序這兩種基本的簡單排序方法。首先從第1個位置開始對全部元素進行選擇,選出全部元素中最小的給該位置,再對第2個位置進行選擇,在剩餘元素中選擇最小的給該位置即可;以此類推,重復進行「最小元素」的選擇,直至完成第(n-1)個位置的元素選擇,則第n個位置就只剩唯一的最大元素,此時不需再進行選擇。使用這種排序時,要注意其中一個不同於冒泡法的細節。舉例說明:序列58539.我們知道第一遍選擇第1個元素「5」會和元素「3」交換,那麼原序列中的兩個相同元素「5」之間的前後相對順序就發生了改變。因此,我們說選擇排序不是穩定的排序演算法,它在計算過程中會破壞穩定性。
快速排序
快速排序的基本思想是:通過一趟排序演算法把所需要排序的序列的元素分割成兩大塊,其中,一部分的元素都要小於或等於另外一部分的序列元素,然後仍根據該種方法對劃分後的這兩塊序列的元素分別再次實行快速排序演算法,排序實現的整個過程可以是遞歸的來進行調用,最終能夠實現將所需排序的無序序列元素變為一個有序的序列。
歸並排序
歸並排序演算法就是把序列遞歸劃分成為一個個短序列,以其中只有1個元素的直接序列或者只有2個元素的序列作為短序列的遞歸出口,再將全部有序的短序列按照一定的規則進行排序為長序列。歸並排序融合了分治策略,即將含有n個記錄的初始序列中的每個記錄均視為長度為1的子序列,再將這n個子序列兩兩合並得到n/2個長度為2(當凡為奇數時會出現長度為l的情況)的有序子序列;將上述步驟重復操作,直至得到1個長度為n的有序長序列。需要注意的是,在進行元素比較和交換時,若兩個元素大小相等則不必刻意交換位置,因此該演算法不會破壞序列的穩定性,即歸並排序也是穩定的排序演算法。
C. 基本排序演算法原理
演算法原理:每次對相鄰的兩個元素進行比較,若前者大於後者則進行交換,如此一趟下來最後一趟的就是最大元素,重復以上的步驟,除了已經確定的元素 。
演算法原理:每次對相鄰的兩個元素進行比較,若前者大於後者則進行交換,如此一趟下來最後一趟的就是最大元素,重復以上的步驟,除了已經確定的元素
演算法步驟
1) 設置兩個變數i、j,排序開始的時候:i=0,j=n-1;
2)第一個數組值作為比較值,首先保存到temp中,即temp=A[0];
3)然後j-- ,向前搜索,找到小於temp後,因為s[i]的值保存在temp中,所以直接賦值,s[i]=s[j]
4)然後i++,向後搜索,找到大於temp後,因為s[j]的值保存在第2步的s[i]中,所以直接賦值,s[j]=s[i],然後j--,避免死循環
5)重復第3、4步,直到i=j,最後將temp值返回s[i]中
6) 然後採用「二分」的思想,以i為分界線,拆分成兩個數組 s[0,i-1]、s[i+1,n-1]又開始排序
排序圖解
演算法原理:從第一個元素開始,左邊視為已排序數組,右邊視為待排序數組,從左往右依次取元素,插入左側已排序數組,對插入新元素的左側數組重新生成有序數組 。需要注意的是,在往有序數組插入一個新元素的過程中,我們可以採用按 順序循環 比較,也可以通過 折半查找法 來找到新元素的位置,兩種方式的效率 取決於數組的數據量
演算法原理:希爾排序也是利用插入排序的思想來排序。希爾排序通過將比較的全部元素分為幾個區域來提升插入排序的性能。這樣可以讓一個元素可以一次性地朝最終位置前進一大步。然後演算法再取越來越小的步長進行排序,演算法的最後一步就是普通的插入排序,但是到了這步,需排序的數據幾乎是已排好的了,插入效率比較高。
排序圖解
選擇排序(Selection sort)是一種簡單直觀的排序演算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。選擇排序的主要優點與數據移動有關。如果某個元素位於正確的最終位置上,則它不會被移動。選擇排序每次交換一對元素,它們當中至少有一個將被移到其最終位置上,因此對n個元素的表進行排序總共進行至多n-1次交換。在所有的完全依靠交換去移動元素的排序方法中,選擇排序屬於非常好的一種。
歸並排序,顧名思義就是一種 「遞歸合並」 的排序方法(這個理解很重要)。對於一個數列,我們把它進行二分處理,依次遞歸下去,然後將小范圍的數進行排序,最後將其合並在一起。就實現了歸並排序。
這實際上是運用了 分治思想 ,顯然,想要把一個數列排好序,最終達到的目的就是它的任何一部分都是有序的。這樣的話,我們可以考慮分別把數列分成N多個部分,讓每個部分分別有序,然後再將其統一,變成所有的東西都有序。這樣就實現了排序。這個想法就叫分治思想。
排序圖解
排序圖解
D. 面試必會八大排序演算法(Python)
一、插入排序
介紹
插入排序的基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據。
演算法適用於少量數據的排序,時間復雜度為O(n^2)。
插入排演算法是穩定的排序方法。
步驟
①從第一個元素開始,該元素可以認為已經被排序
②取出下一個元素,在已經排序的元素序列中從後向前掃描
③如果該元素(已排序)大於新元素,將該元素移到下一位置
④重復步驟3,直到找到已排序的元素小於或者等於新元素的位置
⑤將新元素插入到該位置中
⑥重復步驟2
排序演示
演算法實現
二、冒泡排序
介紹
冒泡排序(Bubble Sort)是一種簡單的排序演算法,時間復雜度為O(n^2)。
它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。
這個演算法的名字由來是因為越小的元素會經由交換慢慢「浮」到數列的頂端。
原理
循環遍歷列表,每次循環找出循環最大的元素排在後面;
需要使用嵌套循環實現:外層循環控制總循環次數,內層循環負責每輪的循環比較。
步驟
①比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
②對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
③針對所有的元素重復以上的步驟,除了最後一個。
④持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
演算法實現:
三、快速排序
介紹
快速排序(Quicksort)是對冒泡排序的一種改進,借用了分治的思想,由C. A. R. Hoare在1962年提出。
基本思想
快速排序的基本思想是:挖坑填數 + 分治法。
首先選出一個軸值(pivot,也有叫基準的),通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
實現步驟
①從數列中挑出一個元素,稱為 「基準」(pivot);
②重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊);
③對所有兩個小數列重復第二步,直至各區間只有一個數。
排序演示
演算法實現
四、希爾排序
介紹
希爾排序(Shell Sort)是插入排序的一種,也是縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法,時間復雜度為:O(1.3n)。
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
·插入排序在對幾乎已經排好序的數據操作時, 效率高, 即可以達到線性排序的效率;
·但插入排序一般來說是低效的, 因為插入排序每次只能將數據移動一位。
基本思想
①希爾排序是把記錄按下標的一定量分組,對每組使用直接插入演算法排序;
②隨著增量逐漸減少,每組包1含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,演算法被終止。
排序演示
演算法實現
五、選擇排序
介紹
選擇排序(Selection sort)是一種簡單直觀的排序演算法,時間復雜度為Ο(n2)。
基本思想
選擇排序的基本思想:比較 + 交換。
第一趟,在待排序記錄r1 ~ r[n]中選出最小的記錄,將它與r1交換;
第二趟,在待排序記錄r2 ~ r[n]中選出最小的記錄,將它與r2交換;
以此類推,第 i 趟,在待排序記錄ri ~ r[n]中選出最小的記錄,將它與r[i]交換,使有序序列不斷增長直到全部排序完畢。
排序演示
選擇排序的示例動畫。紅色表示當前最小值,黃色表示已排序序列,藍色表示當前位置。
演算法實現
六、堆排序
介紹
堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序演算法,它是選擇排序的一種。
利用數組的特點快速指定索引的元素。
基本思想
堆分為大根堆和小根堆,是完全二叉樹。
大根堆的要求是每個節點的值不大於其父節點的值,即A[PARENT[i]] >=A[i]。
在數組的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。
排序演示
演算法實現
七、歸並排序
介紹
歸並排序(Merge sort)是建立在歸並操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
基本思想
歸並排序演算法是將兩個(或兩個以上)有序表合並成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合並為整體有序序列。
演算法思想
自上而下遞歸法(假如序列共有n個元素)
① 將序列每相鄰兩個數字進行歸並操作,形成 floor(n/2)個序列,排序後每個序列包含兩個元素;
② 將上述序列再次歸並,形成 floor(n/4)個序列,每個序列包含四個元素;
③ 重復步驟②,直到所有元素排序完畢。
自下而上迭代法
① 申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合並後的序列;
② 設定兩個指針,最初位置分別為兩個已經排序序列的起始位置;
③ 比較兩個指針所指向的元素,選擇相對小的元素放入到合並空間,並移動指針到下一位置;
④ 重復步驟③直到某一指針達到序列尾;
⑤ 將另一序列剩下的所有元素直接復制到合並序列尾。
排序演示
演算法實現
八、基數排序
介紹
基數排序(Radix Sort)屬於「分配式排序」,又稱為「桶子法」。
基數排序法是屬於穩定性的排序,其時間復雜度為O (nlog(r)m) ,其中 r 為採取的基數,而m為堆數。
在某些時候,基數排序法的效率高於其他的穩定性排序法。
基本思想
將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後,數列就變成一個有序序列。
基數排序按照優先從高位或低位來排序有兩種實現方案:
MSD(Most significant digital) 從最左側高位開始進行排序。先按k1排序分組, 同一組中記錄, 關鍵碼k1相等,再對各組按k2排序分成子組, 之後, 對後面的關鍵碼繼續這樣的排序分組, 直到按最次位關鍵碼kd對各子組排序後. 再將各組連接起來,便得到一個有序序列。MSD方式適用於位數多的序列。
LSD (Least significant digital)從最右側低位開始進行排序。先從kd開始排序,再對kd-1進行排序,依次重復,直到對k1排序後便得到一個有序序列。LSD方式適用於位數少的序列。
排序效果
演算法實現
九、總結
各種排序的穩定性、時間復雜度、空間復雜度的總結:
平方階O(n²)排序:各類簡單排序:直接插入、直接選擇和冒泡排序;
從時間復雜度來說:
線性對數階O(nlog₂n)排序:快速排序、堆排序和歸並排序;
O(n1+§))排序,§是介於0和1之間的常數:希爾排序 ;
線性階O(n)排序:基數排序,此外還有桶、箱排序。
E. 排序方法有哪幾種 排序方法的相關知識
1、排序方法有10種,悉旅緩分別是:冒泡排序、選擇排序、插入排序、希爾排序、歸並排序、快速排序、堆排序、計數排序、桶排序、基數排序。
2、冒泡排序演算法是把較小的元素往前調或者把較大的元素往後調。這種方法主要是通過對相鄰兩個元素進行大小的比較,根據比較結果和演算法規則對該二元素的位置進行交換,這樣逐個依次進行比較和交換,就能達到排序目的。
3、選擇排序演算法的基本思路是為每一個位置睜模選擇當前最小的元素。選擇排序的基本思想是,基於直接選擇排序和堆排序這兩種基本的簡單排序方法。
4、插入排序算鎮森法是基於某序列已經有序排列的情況下,通過一次插入一個元素的方式按照原有排序方式增加元素。
F. 編一程序用簡單選擇排序方法對n個整數排序(從大到小)。 對n個數進行降序排列,簡單選擇排序的演算法思
#include<stdio.h>
int main()
{int i,j,t,n,a[100];
printf("請輸入有幾個整數(<=100):");
scanf("%d",&n);
printf("請輸入這%d個整數: ");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n-1;i++)
{k=i;
for(j=i+1;j<n;j++)
if(a[j]<a[k])
k=j;
t=a[i];a[i]=a[k];a[k]=t;
}
printf("排序以後的數: ");
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf(" ");
return 0;
}
(6)選擇排序演算法思想擴展閱讀:
在簡單選擇排序過程中,所需移動記錄的次數比較少。最好情況下,即待排序記錄初始狀態就已經是正序排列了,則不需要移動記錄。
最壞情況下,即待排序記錄初始狀態是按第一條記錄最小,之後的記錄從小到大順序排列,則需要移動記錄的次數最多為3(n-1)。
簡單選擇排序過程中需要進行的比較次數與初始狀態下待排序的記錄序列的排列情況無關。當i=1時,需進行n-1次比較;當i=2時,需進行n-2次比較;依次類推,共需要進行的比較次數是(n-1)+(n-2)+…+2+1=n(n-1)/2,即進行比較操作的時間復雜度為O(n^2),進行移動操作的時間復雜度為O(n)。
G. 選擇排序演算法的思想是什麼
次序關系,採用分治策略,可在最壞的情況下用O(log n)完成搜索任務。它的基本思想是,將n個元素分成個數大致相同的兩半,取a[n/2]與欲查找的x作比較,如果x=a[n/2]則找到x,演算法終止。如果x<a[n/2],則我們只要在數組a的左半部繼續搜索x(這里假設數組元素呈升序排列)。如果x>a[n/2],則我們只要在數組a的右半部繼續搜索x。二分搜索法的應用極其廣泛,而且它的思想易於理解,但是要寫一個正確的二分搜索演算法也不是一件簡單的事。第一個二分搜索演算法早在1946年就出現了,但是第一個完全正確的二分搜索演算法直到1962年才出現。Bentley在他的著作《Writing Correct Programs》中寫道,90%的計算機專家不能在2小時內寫出完全正確的二分搜索演算法。問題的關鍵在於准確地制定各次查找范圍的邊界以及終止條件的確定,正確地歸納奇偶數的各種情況,其實整理後可以發現它的具體演算法是很直觀的,我們可用C++描述如下:
template<class Type>
int BinarySearch(Type a[],const Type& x,int n)
{
int left=0;
int right=n-1;
while(left<=right){
int middle=(left+right)/2;
if (x==a[middle]) return middle;
if (x>a[middle]) left=middle+1;
else right=middle-1;
}
return -1;
}
模板函數BinarySearch在a[0]<=a[1]<=...<=a[n-1]共n個升序排列的元素中搜索x,找到x時返回其在數組中的位置,否則返回-1。容易看出,每執行一次while循環,待搜索數組的大小減少一半,因此整個演算法在最壞情況下的時間復雜度為O(log n)。在數據量很大的時候,它的線性查找在時間復雜度上的優劣一目瞭然。
選擇排序
基本思想是:每次選出第i小的記錄,放在第i個位置(i的起點是0,按此說法,第0小的記錄實際上就是最小的,有點別扭,不管這么多了)。當i=N-1時就排完了。
直接選擇排序
直選排序簡單的再現了選擇排序的基本思想,第一次尋找最小元素的代價是O(n),如果不做某種特殊處理,每次都使用最簡單的尋找方法,自然的整個排序的時間復雜度就是O(n2)了。
冒泡法
為了在a[1]中得到最大值,我們將a[1]與它後面的元素a[2],a[3],...,a[10]進行比較。首先比較a[1]與a[2],如果a[1]<a[2],則將a[1]與a[2]交換,否則不交換。這樣在a[1]中得到的是a[1]與a[2]中的大數。然後將a[1]與a[3]比較,如果a[1]<a[3],則將a[1]與a[3]交換,否則不交換。這樣在a[1]中得到的是a[1],a[2],a[3]中的最大值,...。如此繼續,最後a[1]與a[10]比較,如果a[1]<a[10],則將a[1]與a[10]交換,否則不交換。這樣在a[1]中得到的數就是數組a的最大值(一共進行了9次比較)。
為了在a[2]中得到次大值,應將a[2]與它後面的元素a[3],a[4],...,a[10]進行比較。這樣經過8次比較,在a[2]是將得到次大值。
如此繼續,直到最後a[9]與a[10]比較,將大數放於a[9],小數放於a[10],全部排序到此結束。
從上面可以看出,對於10個數,需進行9趟比較,每一趟的比較次數是不一樣的。第一趟需比較9次,第二趟比較8次,...,最後一趟比較1次。
以上數組元素的排序,用二重循環實現,外循環變數設為i,內循環變數設為j。外循環重復9次,內循環依次重復9,8,...,1次。每次進行比較的兩個元素,第一個元素與外循環i有關的,用a[i]標識,第二個元素是與內循環j有關的,用a[j]標識,i的值依次為1,2,...,9,對於每一個i, j的值依次為i+1,i+2,...。