1 / 33

Sort( 排序 )

Sort( 排序 ). 授課者 : 驕芸. Outline. Sort Internal Sorting Bubble Sort Selection Sort Insertion Sort Quick Sort Heap Sort External Sorting Merge Sort. Sort. 將一群資料按照 某一種排列的規則 ,重新安排此群資料的次序, 使其形成一個遞增 ( 或遞減 ) 的線性次序關係 。 排序的方法可分為兩種 :. Internal Sorting( 內部排序 ) 將資料先儲存在記憶體內,然後執行排序。

imani-patel
Télécharger la présentation

Sort( 排序 )

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Sort(排序) 授課者:驕芸

  2. Outline • Sort • Internal Sorting • Bubble Sort • Selection Sort • Insertion Sort • Quick Sort • Heap Sort • External Sorting • Merge Sort

  3. Sort • 將一群資料按照某一種排列的規則,重新安排此群資料的次序,使其形成一個遞增(或遞減)的線性次序關係。 • 排序的方法可分為兩種: • Internal Sorting(內部排序) • 將資料先儲存在記憶體內,然後執行排序。 • External Sorting(外部排序) • 資料太大無法全部儲存在記憶體,在排序的過程使用外部儲 存裝置。

  4. Internal Sorting---Bubble Sort • 讓數值大的數字慢慢往右移,就像在水裡的氣泡向上浮一樣。 • 作法: • 由左至右,數字兩兩比對,若前面的數字比後面大,則前後交換,否則不換。 • 例子:我們要將以下的數字從小到大排序, • 26, 5, 81, 7, 63 • Step1: 5, 26, 7, 63, 81 • Step2: 5, 7, 26, 63, 81 • Step3: 5, 7, 26, 63, 81 • Step4: 5, 7, 26, 63, 81 • 第一次排序完,最大值一定被挪到最右邊,why? • 在第二次排序時只須比較前4個值。

  5. Internal Sorting---Bubble Sort Example • 執行效率為O(n2), why? • 最差的情況:元素用相反的順序排列,若有n個元素,總共需要n-1次的外層迴圈。 • 內層迴圈依照外層迴圈遞減,次數為(n-1) 、(n-2)、…、2、1,總合為n(n-1)/2次的比較與交換. • 將數字由小到大排序(泡沫排序法). • void main( ) { int i,j,tmp; int a[5] = {26, 5, 81, 7, 63 }; for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 4; j++ ) { if (a[j] > a[j+1]) { tmp = a[j]; a[j] = a[j+1]; a[j+1] = tmp; } } printf(“Loop %d : ”,i); for ( j = 0; j < 5; j++ ) printf(“%4d”,a[j]); printf(“\n”); system(“pause”); } }

  6. Internal Sorting---Bubble Sort Example a[0] a[1] a[2] a[3] a[4] a[0] a[1] a[2] a[3] a[4] i=0j=0 j=1 j=2 j=3 i=1j=0 j=1 j=2 j=3 a[0] a[1] a[2] a[3] a[4] a[0] a[1] a[2] a[3] a[4] i=3 j=0 j=1 j=2 j=3 i=2 j=0 j=1 j=2 j=3

  7. Internal Sorting---Selection Sort • 從排序的元素中選出最小的一個元素與第一個元素交換。然後從剩下的元素中再選出最小的元素和第二個元素交換,如此重覆下去,直到最後一個元素為止。

  8. Internal Sorting---Selection Sort • 例子:我們要將以下的字元依字典順序排序 • l, k, j, o, a, b • 需要兩層迴圈,外層迴圈執行交換過程,內層迴圈每次找出最小的元素. • 執行效率為O(n2),迴圈執行次數與Bubble Sort相同. 第一次交換 第二次交換第三次交換 第四次交換第五次交換

  9. Selection Sort Example • void select(char *string,int count) • { • int pos; /*目前最小的字元*/ • int i,j; • char temp; • for ( i = 0; i < count - 1; i++ ) /*第一層迴圈,執行交換*/ • { • pos = i; • temp = string[pos]; • for ( j = i + 1; j < count; j++ ) /*第二層迴圈,找尋最小的字元*/ • if ( string[j] < temp ) /*是否更小*/ • { • pos = j; /*新的最小字元*/ • temp = string[j]; • } • string[pos] = string[i]; /*交換兩字元*/ • string[i] = temp; • printf("輸出結果: [%s]\n",string); /*列印交換後字串 */ • } • }

  10. Internal Sorting---Insertion Sort • 將一個記錄插入到一串排序好的記錄。 • 先將前兩個元素排序,然後將第三個元素插入排序好的兩個元素,使其三個元素仍是由小至大排序。 • 重覆操作直到所有元素都排好。 • 優點: • 當字串幾乎排序好時,插入排序法的時間就比較短。 • 不會影響相同元素的資料順序。 • 缺點:執行效率慢,不適合資料量龐大時使用。

  11. Internal Sorting---Insertion Sort • 執行效率為O(n2),why? • 第一層迴圈需插入n-1個元素,第二層回圈將執行1,2,3…n-2,n-1次,合計為n(n-1)/2. • 例子:我們要將以下的字元依字典順序排序 • l, k, j, o, a, b 最初陣列 第一次第二次第三次第四次第五次

  12. Insertion Sort Example • #include <stdlib.h> • #define MAX 20 /*最大字串長度*/ • void insert(char *string,int count) • { • int i,j; • char temp; • for ( i = 1; i < count; i++ ) /* 第一層迴路,插入元素至字串中*/ • { • temp = string[i]; /*建立初值*/ • j = i - 1; /*開始位置*/ • /*空出插入位置,將插入元素放在正確位置*/ • while ( j >= 0 && temp < string[j] ) • { • string[j+1] = string[j]; • j--; • } • string[j+1] = temp; /*插入字元*/ • printf("輸出結果: [%s]\n",string); /*列印交換後字串*/ • } • }

  13. Quick Sort(高等排序) • 將資料分割 • 選擇一個元素為分割標準,將資料分成兩半。 • 其中一半是比標準值大的元素,另外一半是比較小或相等的元素。 • 接著每一半元素使用相同方法分割,直到無法再分割為止。 • 最好的情況就是找出中間值,但是並不容易,所以有兩種常用方式: • 選取陣列元素的第一個. • 選取陣列元素最中間的元素.

  14. 第一部份 都比d小 第二部份 都比d大 Quick Sort 0 1 2 3 4 5 6 7 交換[1],[5] i j 因為i的值已經大於j的值,所以將選擇值與j互換 j i 對這兩個部份再繼續分割

  15. 第一部份 第二部份 第一部份 第二部份 第一部份 第二部份 Quick Sort 第一部份分割後的結果 第二部份分割的結果 最後的結果

  16. void q_sort(char *string,int left,int right) { char partition; /*分割元素*/ char temp; int i,j,k; if ( left < right ) /*是否繼續分割*/ { i = left; /*分割的最左*/ j = right + 1; /*分割的最右*/ partition = string[left]; /*取第一個元素*/ do { do { /*從左往右找,直到大於等於par才停止*/ i++; } while( string[i] < partition ); do { /*從右往左找,直到小於等於par才停止*/ j--; } while( string[j] > partition ); if ( i < j ) { temp = string[i]; /*若有找到滿足前述兩項條件者,就交換資料*/ string[i] = string[j]; string[j] = temp; } } while( i < j ); temp= string[left]; /*若i>=j 則交換j與left的資料*/ string[left] = string[j]; string[j] = temp; printf("輸出結果: "); for ( k = left; k <= right; k++) /*列印處理字串 */ printf("%c",string[k]); printf("\n"); /*換行*/ q_sort(string,left,j-1); /*遞迴呼叫處理第一部份*/ q_sort(string,j+1,right);/*遞迴呼叫處理第二部份*/ } } Quick Sort

  17. Quick Sort • void quick(char *string,int n) • { • q_sort(string,0,n-1); • } • void main() • { • char string[MAX]; /*字串陣列*/ • int count; /*字串長度*/ • printf("輸入欲排序的字串 ==> "); • gets(string); /*讀取字串*/ • count = strlen(string); /*計算字串長度*/ • quick(string,count); /*快速排序法*/ • /*列印排序後字串*/ • printf("\n輸出排序結果: [%s]\n",string); • }

  18. Heap Sort • Heap本身是一棵二元樹,且滿足下列的條件: • 每個父節點都比其左,右子節點的資料大或相等。 • Heap處理步驟: • Step1:由二元樹建立heap. • Step2:輸出heap的樹根,將剩下的二元樹節點重建為heap. • Step3:重覆操作直到所有節點都已輸出.

  19. Heap Sort • 有一棵二元樹如下圖所示: (1) 5 (2) (3) 6 4 (4) (5) (6) (7) 8 2 3 7 (8) (9) 1 9 索引值從1開始, 節點n的左子節點為2*n,右子節點為2*n+1. • 儲存方式如下圖所示: 1 2 3 4 5 6 7 8 9

  20. Heap Sort---調整 • 由中間往回調整. • 如果陣列有n個元素,其中間的位置是n/2. • 此位置的節點保證是葉節點的上一層,所以在調整的過程,可以處理所有的葉節點. • 接著再作如下列的步驟: Step1:找出此節點的左,右節點中資料最大的節點與此節點相比較. (1)如果此節點較大,則不調整. (2)如果此節點比較小,則交換兩節點的資料,然後以交換後的父節點重覆Step1.

  21. (1) (1)首先往回調整的索引值是4(9/2).此時的右子節點比它大,所以作交換. 5 (2) (3) 6 4 (4) (5) (6) (7) 8 2 3 7 (8) (9) 1 9 (1) (2)因為索引值9的節點無子節點,所以結束. 5 (2) (3) 6 4 (4) (5) (6) (7) 9 2 3 7 (8) (9) 1 8

  22. (1) (3)接著處理索引值3的節點.因為右節點較大,所以作交換. 5 (2) (3) 6 4 (4) (5) (6) (7) 9 2 3 7 (8) (9) 1 8 (1) (4)因為索引值7的節點無子節點,所以結束. 5 (2) (3) 6 7 (4) (5) (6) (7) 9 2 3 4 (8) (9) 1 8

  23. (1) (5)接著處理索引值2的節點.因為右節點較大,所以作交換. 5 (2) (3) 6 7 (4) (5) (6) (7) 9 2 3 4 (8) (9) 1 8 (1) (6)因為索引值4的節點有子節點,所以繼續比較,結果左子節點8比較大,作交換. 5 (2) (3) 9 7 (4) (5) (6) (7) 6 2 3 4 (8) (9) 1 8

  24. (1) (7)接著處理索引值1的節點.因為左節點較大,所以作交換. 5 (2) (3) 9 7 (4) (5) (6) (7) 8 2 3 4 (8) (9) 1 6 (1) (8)因為索引值2的節點有子節點,所以繼續比較子節點,結果左子節點較大,作交換. 9 (2) (3) 5 7 (4) (5) (6) (7) 8 2 3 4 (8) (9) 1 6

  25. (1) (9)接著處理索引值4的節點.因為右節點較大,所以作交換. 9 (2) (3) 8 7 (4) (5) (6) (7) 5 2 3 4 (8) (9) 1 6 (1) (10)因為索引值9的節點沒有子節點,所以結束調整. 9 (2) (3) 8 7 (4) (5) (6) (7) 6 2 3 4 (8) (9) 1 5

  26. #include <stdlib.h> /* 調整累堆 */ void adjust_heap(int *heap,int root,int len) { int done; /* 是否可結束的變數 */ int j; int temp; j = 2 * root; /* 子節點指標 */ temp = heap[root]; /* 累堆的根值 */ done = 0; /* 建立變數 */ while ( j <= len && !done ) /* 主迴路 */ { if ( j < len ) /* 從左,右子節點中找最大的子節點*/ if ( heap[j] < heap[j+1] ) j++; /* 下一節點 */ if ( temp >= heap[j] ) /* 比較樹根值 */ done = 1; /* 結束 */ else { heap[j/2] = heap[j]; /* 父節點是目前節點 */ j = 2 * j; /* 其子節點 */ } } heap[j/2] = temp; /*父節點為根值 */ } /* 累堆排序 */ void heap(int *heap,int len) { int i,j,temp; for ( i = ( len / 2 ); i >= 1; i-- ) /*將二元樹轉成累堆*/ adjust_heap(heap,i,len); printf("\n累堆的內容: "); for ( j = 1; j < 10; j++ ) /*列出累堆的內容 */ printf("[%d]",heap[j]); printf("\n"); /*換行 */ for ( i = len - 1; i >= 1; i-- ) /*累堆排序主迴路*/ { temp = heap[i+1]; /*交換最後元素:heap[1]與heap[i+1]*/ heap[i+1] = heap[1]; heap[1] = temp; adjust_heap(heap,1,i); /*重建累堆 */ printf("\n處理內容: "); for ( j = 1; j < 10; j++ ) /*列出處理內容*/ printf("[%d]",heap[j]); } } Heap Sort

  27. Heap Sort • /* 主程式: 將陣列資料用累堆排序法來排序. */ • int main() • { • /*二元樹節點資料*/ • int data[10] = { 0, 5, 6, 4, 8, 2, 3, 7, 1, 9 }; • int i; • printf("二元樹的內容: "); • for ( i = 1; i < 10; i++ ) /* 列出二元樹內容 */ • printf("[%d]",data[i]); • heap(data,9); /* 累堆排序法 */ • printf("\n\n輸出排序結果: "); • for ( i = 1; i < 10; i++ ) /* 列出最後內容 */ • printf("[%d]",data[i]); • printf("\n"); • system("pause"); • return 0; • }

  28. Heap Sort Result

  29. Merge Sort • 外部儲存裝置最常用的排序方法. Step1:將資料分成數個檔案,其中大小是可以載入記憶體空間,然後使用適當的內部排序執行,最後將排序完的資料寫回檔案. Step2:將Step1建立的檔案,二個二個合併成為一個檔案,等到全部的檔案都合併成一個檔案,就完成排序.

  30. Merge Sort 1 2 3 4 5 6 7

  31. Merge Sort 檔案1 檔案2

  32. void merge(FILE *merge,FILE *sort1,FILE *sort2,int len) { int s1=0,s2=0; /* 資料計數 */ char c,c1,c2; c1 = getc(sort1); /* 讀取第一個檔案 */ c2 = getc(sort2); /* 讀取第二個檔案 */ while ( 1 ) { if ( c1 < c2 ) /* 比較兩個值*/ { /* 第一個檔案小, 存入主檔 */ putc(c1,merge); s1++; if ( s1 < len ) /* 是否未讀完 */ c1 = getc(sort1); /* 繼續讀取第一個檔案*/ else break; /* 第一個檔案已讀完,跳出迴路 */ } else { /* 第二個檔案小, 存入主檔 */ putc(c2,merge); s2++; if ( s2 < len ) /* 是否未讀完 */ c2 = getc(sort2); /* 讀取第二個檔案 */ else break; } } /*第二個檔案已讀完, 跳出迴路*/ /* 第一個檔案是否是已讀取的最後一筆 */ if ( s1 < len ) { putc(c1,merge); /* 存入主檔*/ s1++; /* 計數加一*/ } /* 第二個檔案是否是已讀取的最後一筆 */ if ( s2 < len ) { putc(c2,merge); /* 存入主檔 */ s2++; } /* 第一個檔案 */ while ( s1 < len ) /* 取出剩下的資料 */ { c = getc(sort1); /* 讀取第一個檔案 */ putc(c,merge); /* 存入主檔 */ s1++; } /* 第二個檔案 */ while ( s2 < len ) /* 取出剩下的資料 */ { c = getc(sort2); /* 讀取第二個檔案*/ putc(c,merge); /* 存入主檔 */ s2++; } } Merge Sort

  33. Merge Sort • /*合併排序*/ • #include <stdio.h> • #define LEN 4 /* 最大元素個數*/ • /* 主程式: 讀取兩個檔案內容, 接著用合併排序法來排序. */ • int main() • { • FILE *fp; /* 主檔指標 */ • FILE *fp1; /* 第一資料檔案指標*/ • FILE *fp2; /* 第二資料檔案指標 */ • fp = fopen("result.txt","r+"); /* 開啟主檔 */ • if ( fp == NULL ) • printf("主檔開啟錯誤! \n"); • else • fp1 = fopen("sort1.txt","r+"); /*開啟第一資料檔案*/ • if ( fp1 == NULL ) • printf("第一資料檔開啟錯誤! \n"); • else • { • fp2 = fopen("sort2.txt","r+"); /*開啟第二資料檔案*/ • if ( fp2 == NULL ) • printf("第二資料檔開啟錯誤! \n"); • else • { • printf("資料處理中, 請稍待. . . \n"); • merge(fp,fp1,fp2,LEN); /*合併排序法*/ • printf("資料處理完成! \n"); • fclose(fp); /* 關檔 */ • fclose(fp1); • fclose(fp2); }} • system("pause"); • return 0; • } 請先建立好三個檔:sort1.txt,sort2.txt,result.txt

More Related