C語言歸排與計(jì)排深度理解
歸并排序:是創(chuàng)建在歸并操作上的一種有效的排序算法。算法是采用分治法(Divide and Conquer)的一個非常典型的應(yīng)用,且各層分治遞歸可以同時進(jìn)行。歸并排序思路簡單,速度僅次于快速排序,為穩(wěn)定排序算法,一般用于對總體無序,但是各子項(xiàng)相對有序的數(shù)列。
1. 基本思想
歸并排序是用分治思想,分治模式在每一層遞歸上有三個步驟:
- 分解(Divide):將n個元素分成個含n/2個元素的子序列。
- 解決(Conquer):用合并排序法對兩個子序列遞歸的排序。
- 合并(Combine):合并兩個已排序的子序列已得到排序結(jié)果。
歸并排序的特性總結(jié):
1. 歸并的缺點(diǎn)在于需要O(N)的空間復(fù)雜度,歸并排序的思考更多的是解決在磁盤中的外排序題。
2. 時間復(fù)雜度:O(N*logN)
3. 空間復(fù)雜度:O(N)
4. 穩(wěn)定性:穩(wěn)定

這是歸并排序的主要概念。
歸并排序有遞歸和非遞歸兩種,我們首先來實(shí)現(xiàn)遞歸的代碼
代碼
//歸并遞歸
void _MergeSore(int* arr, int left, int right, int* tmp)
{
//遞歸結(jié)束條件
if (left >= right)
return;
//int min = left + ((right - left) >> 1);
int min = (left + right) / 2;
//遞歸開始
_MergeSore(arr, left, min, tmp);
_MergeSore(arr, min + 1, right, tmp);
//排序開始
int begin1 = left, end1 = min;
int begin2 = min + 1, end2 = right;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
tmp[i++] = arr[begin1++];
/*i++;
begin1++;*/
}
if (arr[begin1] >= arr[begin2])
{
tmp[i++] = arr[begin2++];
/*i++;
begin2++;*/
}
}
while (begin1 <= end1)
{
tmp[i++] = arr[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = arr[begin2++];
}
//將建立的數(shù)組拷貝到原數(shù)組中
for (int i = 0; i <= right; i++)
{
arr[i] = tmp[i];
}
}
//歸并排序
void MergeSort(int* arr, int n)
{
//先建立一個數(shù)組,用來存放排序的元素
int* tmp = (int*)malloc(sizeof(int) * (n));
if (tmp == NULL)
{
perror("perror,file");
return;
}
//歸并函數(shù)實(shí)現(xiàn)
_MergeSore(arr, 0, n - 1, tmp);
//銷毀新建數(shù)組,防止內(nèi)存泄漏
free(tmp);
//防止野指針
tmp = NULL;
}下面是非遞歸的寫法,非遞歸的思想與遞歸的思想幾乎一樣,大家可以自己想下過程。
- 申請空間,使其大小為兩個已經(jīng)排序序列之和,該空間用來存放合并后的序列
- 設(shè)定兩個指針,最初位置分別為兩個已經(jīng)排序序列的起始位置
- 比較兩個指針?biāo)赶虻脑?,選擇相對小的元素放入到合并空間,并移動指針到下一位置
- 重復(fù)步驟③直到某一指針到達(dá)序列尾
- 將另一序列剩下的所有元素直接復(fù)制到合并序列尾
void _MergeSoreNonR1(int* arr, int left, int right, int* tmp)
{
int gap = 1;
int i = 0;
while (gap <= right)
{
for (i = 0; i <= right; i += 2 * gap)
{
//[i,I+gap-1] [i+gap,2*gap-1]
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
//printf(" %d", end2);
if (end1 > right)
end1 = right;
if (begin2 > right)
{
begin2 = right + 1;
end2 = right;
}
if (end2 > right)
end2 = right;
int index = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
tmp[index++] = arr[begin1++];
}
if (arr[begin1] >= arr[begin2])
{
tmp[index++] = arr[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = arr[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = arr[begin2++];
}
}
for (i = 0; i <= right; i++)
{
arr[i] = tmp[i];
}
gap *= 2;
}
}
void MergeSortNonR(int* arr, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc,file");
return;
}
_MergeSoreNonR1(arr, 0, n-1, tmp);
free(tmp);
tmp = NULL;
}下面來看計(jì)數(shù)排序
計(jì)數(shù)排序不用比較兩個數(shù)的大小,它的做法是統(tǒng)計(jì)哪個元素出現(xiàn)的次數(shù),然后通過這個元素出現(xiàn)的次數(shù)來排序。
計(jì)數(shù)算法只能使用在已知序列中的元素在0-k之間,且要求排序的復(fù)雜度在線性效率上。 Â 計(jì)數(shù)排序和基數(shù)排序很類似,都是非比較型排序算法。但是,它們的核心思想是不同的,基數(shù)排序主要是按照進(jìn)制位對整數(shù)進(jìn)行依次排序,而計(jì)數(shù)排序主要側(cè)重于對有限范圍內(nèi)對象的統(tǒng)計(jì)?;鶖?shù)排序可以采用計(jì)數(shù)排序來實(shí)現(xiàn)。
計(jì)數(shù)排序的特性總結(jié):
1. 計(jì)數(shù)排序在數(shù)據(jù)范圍集中時,效率很高,但是適用范圍及場景有限。
2. 時間復(fù)雜度:O(MAX(N,范圍))
3. 空間復(fù)雜度:O(范圍)
4. 穩(wěn)定性:穩(wěn)定

代碼實(shí)現(xiàn)
void CountSort(int* arr, int n)
{
//確定數(shù)組開辟的大小
int max = arr[0], min = arr[0];
for (int i = 1; i < n; i++)
{
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
int range = max - min + 1;
//建立一個數(shù)組
int* count = (int*)malloc(sizeof(int) * range);
if (count == NULL)
{
perror("malloc file");
return NULL;
}
memset(count, 0, sizeof(int) * range);
for (int i = 0; i < n; i++)
{
count[arr[i]-min]++;
}
int j = 0;
for (int i = 0; i < n; i++)
{
while (count[i]--)
{
arr[j] = i+min;
j++;
}
}
free(count);
count = NULL;
}下面是一張八大排序的比較圖

到此這篇關(guān)于C語言歸排與計(jì)排深度理解的文章就介紹到這了,更多相關(guān)歸排與計(jì)排理解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在C++中實(shí)現(xiàn)高效的數(shù)組原地輪轉(zhuǎn)的方法總結(jié)
在 C++ 中,可以通過多種方式實(shí)現(xiàn)數(shù)組的輪轉(zhuǎn)操作,以下是幾種常見的實(shí)現(xiàn)方法及其對應(yīng)的代碼示例,文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下2025-04-04
VS2022新建項(xiàng)目時沒有ASP.NET Web應(yīng)用程序(.NET Framework)
本文主要介紹了VS2022新建項(xiàng)目時沒有ASP.NET Web應(yīng)用程序的解決,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10
C++輸出上三角/下三角/菱形/楊輝三角形(實(shí)現(xiàn)代碼)
本篇文章是對C++中輸出上三角/下三角/菱形/楊輝三角形的示例代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-07-07

