C語言超詳細(xì)講解排序算法下篇
上期學(xué)習(xí)完了前四個(gè)排序,這期我們來學(xué)習(xí)剩下的三個(gè)排序
1、冒泡排序
冒泡排序是我們相對最好理解的個(gè)排序,但是有些小優(yōu)化的地方我會(huì)指出來,我們先看圖解:
void BubbleSort(int* a, int n)//升序 { //時(shí)間復(fù)雜度O(N^2) while (n > 0) { int exchange = 0; for (int i = 1; i < n; ++i)//防止越界訪問 { if (a[i - 1] > a[i]) { Swap(&a[i - 1], &a[i]);//交換 exchange = 1; } } if (exchange == 0) { break; } --n; } }
代碼分析:我們每排完一趟,就可以確定最后一個(gè)位置的數(shù),再者我們定義了一個(gè)exchange來判斷在排序過程中是否發(fā)生了交換,如果沒有發(fā)生交換,證明此數(shù)組已經(jīng)有序,我們可以直接跳出循環(huán),避免不必要的循環(huán)!
冒泡排序的特性總結(jié):
1. 冒泡排序是一種非常容易理解的排序
2. 時(shí)間復(fù)雜度:O(N^2) 、空間復(fù)雜度:O(1)
3. 穩(wěn)定性:穩(wěn)定
2、快速排序 ( 三種方法 )
快速排序是Hoare于1962年提出的一種二叉樹結(jié)構(gòu)的交換排序方法。
基本思想為:任取待排序元素序列中的某元素作為基準(zhǔn)值,按照該排序碼將待排序集合分割成兩子序列,左子序列中所有元素均小于基準(zhǔn)值,右子序列中所有元素均大于基準(zhǔn)值,然后最左右子序列重復(fù)該過程,直到所有元素都排列在相應(yīng)位置上為止。
第一種方法是我們最常見的挖坑法:
代碼實(shí)現(xiàn)如下:
void QuickSort(int* a, int left, int right)//升序 { if (left >= right) { return; } int begin = left; int end = right; int pivot = begin; int key = a[begin]; while (begin < end) { //右邊找小 while (begin < end && a[end] >= key) //這里如果不寫begin<end的話可能會(huì)出現(xiàn)越界訪問 { --end; } //小的放到左邊的坑里,自己形成了新的坑位 a[pivot] = a[end]; pivot = end; //左邊找大 while (begin < end && a[begin] <= key) { ++begin; } //大的放到左邊的坑里,自己形成了新的坑位 a[pivot] = a[begin]; pivot = begin; } //當(dāng)begin和end相遇,證明他們兩都到了坑的位置 pivot = begin;//隨便給一個(gè) a[pivot] = key; //[left, pivot - 1] pivot [pivot+ 1, right] //左子區(qū)間和右子區(qū)間有序,我們就有序了,如何讓他們有序呢?分治遞歸 QuickSort(a, left, key - 1); QuickSort(a, key + 1, right); } //函數(shù)傳參:QuickSort(arr, 0, sizeof(arr) / sizeof(int) - 1);
第二種方法左右指針法:
代碼實(shí)現(xiàn)如下:
void QuickSort(int* a, int left, int right)//升序 { if (left >= right) { return; } int begin = left; int end = right; int keyi = begin; while (begin < end) { //找小 while (begin < end && a[end] >= a[keyi]) { --end; } //找大 while (begin < end && a[begin] <= a[keyi]) { ++begin; } Swap(&a[begin], &a[end]); } Swap(&a[begin], &a[keyi]); keyi = begin; //[left, keyi - 1] keyIndex [keyi + 1, right] //左子區(qū)間和右子區(qū)間有序,我們就有序了,如何讓他們有序呢?分治遞歸 QuickSort(a, left, keyi - 1); QuickSort(a, keyi + 1, right); }
第三種方法前后指針法:
代碼實(shí)現(xiàn)如下:
void QuickSort(int* a, int left, int right)//升序 { if (left >= right) { return; } int keyi = left; int prev = left; int cur = left + 1; while (cur <= right) { //++prev != cur為了防止自己跟自己交換造成不必要的消耗 if (a[cur] < a[keyi] && ++prev != cur) { Swap(&a[prev], &a[cur]); } ++cur; } Swap(&a[keyi], &a[prev]); keyi = prev; //[left, keyi - 1] keyi [keyi + 1, right] //左子區(qū)間和右子區(qū)間有序,我們就有序了,如何讓他們有序呢?分治遞歸 QuickSort(a, left, keyi - 1); QuickSort(a, keyi + 1, right); }
3、歸并排序
基本思想: 歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法 (Divide and Conquer)的一個(gè)非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子序列段間有序。若將兩個(gè)有序表合并成一個(gè)有序表,稱為二路歸并。
歸并排序我們思想還是和快排思想差不多采用分治算法,當(dāng)數(shù)組被分為單獨(dú)一個(gè)元素就是有序的了(見上圖),在接著歸并到一個(gè)數(shù)組中,即可實(shí)現(xiàn)排序!
代碼實(shí)現(xiàn)如下:
void _MergeSort(int* a, int left, int right, int* tmp) { if (left >= right) return; int mid = (left + right) >> 1; // 假設(shè)[left, mid] [mid + 1, right] 有序,那么我們就可以歸并了 _MergeSort(a, left, mid, tmp); _MergeSort(a, mid + 1, right, tmp); //歸并 int begin1 = left, end1 = mid; int begin2 = mid + 1, end2 = right; int index = left; while (begin1 <= end1 && begin2 <= end2) { if (a[begin1] < a[begin2]) { tmp[index++] = a[begin1++]; } else { tmp[index++] = a[begin2++]; } } while (begin1 <= end1) { tmp[index++] = a[begin1++]; } while (begin2 <= end2) { tmp[index++] = a[begin2++]; } //拷貝回去 for (int i = left; i <= right; ++i) { a[i] = tmp[i]; } } void MergeSort(int* a, int n) { int* tmp = (int*)malloc(sizeof(int) * n); _MergeSort(a, 0, n - 1, tmp); free(tmp); }
4、排序算法復(fù)雜度及穩(wěn)定性分析
穩(wěn)定性:假定在待排序的記錄序列中,存在多個(gè)具有相同的關(guān)鍵字的記錄,若經(jīng)過排序,這些記錄的相對次序保持不變,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍 在r[j]之前,則稱這種排序算法是穩(wěn)定的;否則稱為不穩(wěn)定的。
gitee(碼云):Mercury. (zzwlwp) - Gitee.com
到此這篇關(guān)于C語言超詳細(xì)講解排序算法下篇的文章就介紹到這了,更多相關(guān)C語言 排序算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c語言實(shí)現(xiàn)足球比賽積分統(tǒng)計(jì)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了c語言實(shí)現(xiàn)足球比賽積分統(tǒng)計(jì)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05C++中靜態(tài)成員函數(shù)與靜態(tài)成員變量(static )
這篇文章主要介紹了C++中靜態(tài)成員函數(shù)與靜態(tài)成員變量(static )的相關(guān)資料,需要的朋友可以參考下2017-06-06SublimeText編譯C開發(fā)環(huán)境設(shè)置
這篇文章主要介紹了使用SublimeText編譯C代碼的開發(fā)環(huán)境設(shè)置,大家參考使用2013-11-11