国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)

這篇具有很好參考價值的文章主要介紹了排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一:歸并排序

(1)歸并排序的基本思想

(2)遞歸版本

①實現(xiàn)思路

②合并

③遞歸實現(xiàn)有序

④最終代碼

(3)非遞歸版本

①實現(xiàn)思路

②控制分組

③最終代碼

(4)時間,空間復雜度分析

(5)小結(jié)

二:計數(shù)排序

(1)計數(shù)排序的基本思想

(2)實現(xiàn)思路

(3)圖解加最終代碼

(4)時間,空間復雜度分析

(5)小結(jié)


一:歸并排序

(1)歸并排序的基本思想

歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個非常典型的應用。
將已有序的子序列合并,得到完全有序的序列;
即先使每個子序列有序,再使子序列段間有序。若將
兩個有序數(shù)組合并成一個有序數(shù)組,稱為二路歸并。
圖解:
排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)

(2)遞歸版本

①實現(xiàn)思路

【1】把待排序數(shù)組從中間分成兩個子數(shù)組,直到無法分割(即每個子數(shù)組只有一個元素)。

【2】對每個子數(shù)組進行歸并排序,即遞歸調(diào)用歸并排序函數(shù)。

【3】合并兩個有序子數(shù)組,得到一個有序的數(shù)組(這里需要輔助數(shù)組來實現(xiàn)),然后把這個有序數(shù)組拷貝到原數(shù)組中。

【4】重復步驟3,直到所有的子數(shù)組合并成一個有序的數(shù)組,排序完成。


②合并

合并兩個有序數(shù)組需要輔助數(shù)組tmp,大致思路就是遍歷兩個區(qū)間,拿出兩個數(shù)組中較小值放在tmp中,合并成有序后再拷貝回原數(shù)組。

圖解:

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)

這里循環(huán)已經(jīng)結(jié)束但我們需要把沒結(jié)束的一方拷貝到tmp中

    //把沒結(jié)束的一方拷貝到tmp中
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

合并的代碼:

//這個時候左右已經(jīng)有序,合并
	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	int i = left;

	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin2] < a[begin1])
		{
			tmp[i++] = a[begin2++];
		}
		else
		{
			tmp[i++] = a[begin1++];
		}
	}

	//把沒結(jié)束的一方拷貝到tmp中
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	//拷貝回去
	//注意這里合并了的有序區(qū)間為[left,right]
	//別的區(qū)間不一定有序,拷貝時要注意
	for (int j = left; j <= right; j++)
	{
		a[j] = tmp[j];
	}

③遞歸實現(xiàn)有序

圖解(以左區(qū)間為例):

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)


④最終代碼

void _MergeSort(int* a, int left,int right,int* tmp)
{
	//只有一個元素(可看成有序)或者區(qū)域不存在,返回
	if (left >= right)
	{
		return;
	}
	int mid = left + (right - left) / 2;
	//先遞歸排序左區(qū)間,后遞歸排序右區(qū)間
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);

	//這個時候左右已經(jīng)有序,合并
	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	int i = left;

	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin2] < a[begin1])
		{
			tmp[i++] = a[begin2++];
		}
		else
		{
			tmp[i++] = a[begin1++];
		}
	}

	//把沒結(jié)束的一方拷貝到tmp中
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	//拷貝回去
	//注意這里合并了的有序區(qū)間為[left,right]
	//別的區(qū)間不一定有序,拷貝時要注意
	for (int j = left; j <= right; j++)
	{
		a[j] = tmp[j];
	}
}
//歸并排序
void MergeSort(int* a, int n)
{
	//臨時數(shù)組
	int* tmp = (int*)malloc(sizeof(int) * n);
	
	//調(diào)用子函數(shù)進行排序
	_MergeSort(a, 0,n-1,tmp);

	//銷毀
	free(tmp);
	//這里置不置空沒影響
	tmp = NULL;
}

(3)非遞歸版本

①實現(xiàn)思路

【1】首先將待排序數(shù)組中的每一個元素看成是一個大小為1的有序區(qū)間。

【2】然后將相鄰的兩個區(qū)間(保證每次合成的都是相鄰區(qū)間,依靠間距gap來控制)合并成一個更大的有序區(qū)間,這可以通過歸并排序中的合并操作來實現(xiàn)。

【3】重復步驟2,每次將相鄰的兩個有序子數(shù)組合并成更大的有序子數(shù)組,直到得到一個完整的有序數(shù)組。

【4】最終得到的有序數(shù)組就是排序結(jié)果。


②控制分組

關(guān)于間距gap對循環(huán)的控制:

gap=1,范圍為1(gap)的區(qū)間是有序的,合并相鄰兩個區(qū)間,拷貝。

gap=gap*2=2,范圍為2(gap)的區(qū)間是有序的,合并相鄰兩個區(qū)間,拷貝。

gap=gap*2=4,范圍為4(gap)的區(qū)間是有序的,合并相鄰兩個區(qū)間,拷貝。

………………

一直到gap>=n(這個時候數(shù)組前n個數(shù)一定有序,n是數(shù)組元素個數(shù),結(jié)束循環(huán))


代碼:

    int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = i + gap;
			int end2 = i + gap * 2 - 1;
			int index = i;

			while (begin1 <= end1 && begin2 <= end2)
			{
				//begin1小,放a[begin1]
				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 j = i; j <= end2; j++)
			{
				a[j] = tmp[j];
			}
		}
		gap *= 2;
	}

圖解:

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)

我們可以看到像前面那樣進行分組是有很大可能越界的,那我們應該怎么做呢?

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)

?排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)

合并拷貝前加上區(qū)間判斷和修正后,排序不會越界了

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)


③最終代碼

//歸并非遞歸
void MergeSortNonR(int* a, int n)
{
	//臨時數(shù)組
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		printf("malloc error\n");
		exit(-1);
	}

	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = i + gap;
			int end2 = i + gap * 2 - 1;
			int index = i;

			//end1,begin2,end2都有可能越界
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}

			while (begin1 <= end1 && begin2 <= end2)
			{
				//begin1小,放a[begin1]
				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 j = i; j <= end2; j++)
			{
				a[j] = tmp[j];
			}
		}
		gap *= 2;
	}

	//釋放
	free(tmp);
	tmp = NULL;
}

(4)時間,空間復雜度分析

空間復雜度:

開辟了空間大小和原數(shù)組相同的輔助數(shù)組,故空間復雜度為O(N)

時間復雜度:

【1】在歸并排序的每一次合并操作中,需要將兩個有序數(shù)組合并成一個有序數(shù)組,這個過程需要比較兩個有序數(shù)組中所有元素,因此時間復雜度為O(N)

【2】在歸并排序中,每次將數(shù)組劃分成兩個長度大致相等的子數(shù)組,因此可以得到一個完全二叉樹,其深度大約為logN。每層的合并操作的時間復雜度為O(N),因此整個算法的時間復雜度為O(N*logN)


(5)小結(jié)

歸并排序的效率還不錯,但是有O(N)的空間復雜度,更多是應用在解決磁盤中的外排序問題。

另外控制邊界的方法并不止上面一種

除了右區(qū)間不在數(shù)組中(左右都越界)直接跳出(這個時候沒有對tmp進行操作,對應位置為隨機值)

我們也可以把右區(qū)間人為修改為不存在(begin>end),這種情況下即使不需要合并也會拷貝到tmp中,我們就可以一次大循環(huán)結(jié)束再進行拷貝(拷貝一層),但是這樣不是很好理解

代碼:

//歸并非遞歸
void MergeSortNonR1(int* a, int n)
{
	//臨時數(shù)組
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		printf("malloc error\n");
		exit(-1);
	}

	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2*gap)
		{
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = i + gap;
			int end2 = i + gap * 2 - 1;
			int index = i;

			//修正,讓左區(qū)間不越界
			if (end1 >= n)
			{
				end1 = n - 1;
			}
			//修正,讓右區(qū)間不存在
			if (begin2 >= n)
			{
				//begin2 > end2,區(qū)間不存在
				begin2 = n ;
				end2 = n - 1;
			}
			//修正,讓右區(qū)間不越界
			if (end2 >= n)
			{
				end2 = n - 1;
			}

			while (begin1 <= end1 && begin2 <= end2)
			{
				//begin1小,放a[begin1]
				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 j = 0; j < n; j++)
		{
			a[j] = tmp[j];
		}
		gap *= 2;
	}
	
	//釋放
	free(tmp);
	tmp = NULL;
}

二:計數(shù)排序

(1)計數(shù)排序的基本思想

對于給定的輸入序列中的每一個元素x,確定出小于x的元素個數(shù)

這樣就可以直接把x放到以小于x的元素個數(shù)為下標的輸出序列的對應位置上。

(這里其實是相對位置的概念,比如數(shù)組中最小值為0,它對應下標0位置,最小值為1000,也是對應下標0位置)


(2)實現(xiàn)思路

【1】遍歷一遍,找出最大值和最小值

【2】依據(jù)最大值和最小值的差值來開辟輔助數(shù)組tmp

【3】計數(shù),記錄數(shù)組元素出現(xiàn)次數(shù)

【4】遍歷tmp數(shù)組,進行拷貝


(3)圖解加最終代碼

圖解:

排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)


最終代碼:

//計數(shù)排序
void CountSort(int* a, int n)
{
	//找出最大和最小
	int max = a[0];
	int min = a[0];
	int i = 0;
	for (int i = 1; i < n; i++)
	{
		if (a[i] > max)
		{
			max = a[i];
		}
		if (a[i] < min)
		{
			min = a[i];
		}
	}

	//開空間加初始化
	int* tmp = (int*)malloc(sizeof(int) * (max - min + 1));
	if (tmp == NULL)
	{
		printf("malloc error\n");
		exit(-1);
	}
	//必須初始化為0
	memset(tmp, 0, sizeof(int) * (max - min + 1));

	//計數(shù)
	for (i = 0; i < n; i++)
	{
		tmp[a[i]-min]++;
	}

	//拷貝
	int j = 0;
	for (i = 0; i < max - min + 1; i++)
	{
		while (tmp[i]--)
		{
			a[j++] = i + min;
		}
	}
}

(4)時間,空間復雜度分析

空間復雜度:

開辟了空間大小為range(max-min+1)的輔助數(shù)組,故空間復雜度為O(range)

空間復雜度:

遍歷a找最大和最小為O(N)

遍歷a計數(shù)為O(N)

遍歷range為O(range)

時間復雜度為O(max(N,range))


(5)小結(jié)

計數(shù)排序是一種非比較的排序,它不需要進行數(shù)據(jù)間的比較。

算法設計上非常巧妙,時間復雜度最快可以達到O(N),但是有一定的局限性

比如正負數(shù)同時存在或者數(shù)據(jù)大小浮動很大(1,2,3,1000000)的情況,可能導致空間的大量浪費,效率也會有所下降文章來源地址http://www.zghlxwxcb.cn/news/detail-439704.html

到了這里,關(guān)于排序篇:歸并排序的遞歸,非遞歸以及計數(shù)排序的實現(xiàn)(C語言)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 【C語言】數(shù)據(jù)結(jié)構(gòu)——排序三(歸并與計數(shù)排序)

    【C語言】數(shù)據(jù)結(jié)構(gòu)——排序三(歸并與計數(shù)排序)

    ??個人主頁?? ?個人專欄——數(shù)據(jù)結(jié)構(gòu)學習? ??點擊關(guān)注??一起學習C語言???? 我們在前面學習了排序,包括直接插入排序,希爾排序,選擇排序,堆排序,冒泡排序和快排。 今天我們來講一講歸并排序和計數(shù)排序。 關(guān)注博主或是訂閱專欄,掌握第一消息。 歸并排序的

    2024年01月19日
    瀏覽(20)
  • 快速排序、希爾排序、歸并排序、堆排序、插入排序、冒泡排序、選擇排序(遞歸、非遞歸)C語言詳解

    快速排序、希爾排序、歸并排序、堆排序、插入排序、冒泡排序、選擇排序(遞歸、非遞歸)C語言詳解

    1.排序的概念及其運用 1.1排序的概念 排序 :所謂排序,就是使一串記錄,按照其中的某個或某些的大小,遞增或遞減的排列起來的操作。 穩(wěn)定性 :假定在待排序的記錄序列中,存在多個具有相同的的記錄,若經(jīng)過排序,這些記錄的相對次序保持不變,即在原序

    2024年02月03日
    瀏覽(26)
  • 八大排序算法之歸并排序(遞歸實現(xiàn)+非遞歸實現(xiàn))

    八大排序算法之歸并排序(遞歸實現(xiàn)+非遞歸實現(xiàn))

    目錄 一.歸并排序的基本思想 歸并排序算法思想(排升序為例) 二.兩個有序子序列(同一個數(shù)組中)的歸并(排升序) 兩個有序序列歸并操作代碼: 三.歸并排序的遞歸實現(xiàn) 遞歸歸并排序的實現(xiàn):(后序遍歷遞歸) 遞歸函數(shù)抽象分析:? 四.非遞歸歸并排序的實現(xiàn) 1.非遞歸歸并排序算法思想

    2024年02月03日
    瀏覽(20)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】歸并排序詳解:歸并排序算法,歸并排序非遞歸實現(xiàn)

    【數(shù)據(jù)結(jié)構(gòu)與算法】歸并排序詳解:歸并排序算法,歸并排序非遞歸實現(xiàn)

    歸并排序是一種經(jīng)典的排序算法,它使用了分治法的思想。下面是歸并排序的算法思想: 遞歸地將數(shù)組劃分成較小的子數(shù)組,直到每個子數(shù)組的長度為1或者0。 將相鄰的子數(shù)組合并,形成更大的已排序的數(shù)組,直到最終得到一個完全排序的數(shù)組。 歸并排序的過程可以分為三

    2024年01月22日
    瀏覽(32)
  • 快速排序和歸并排序(遞歸實現(xiàn))

    算法采用了分治的思想 arr先保證局部有序,再慢慢變得整體有序 實際并沒有分割數(shù)組

    2024年04月14日
    瀏覽(22)
  • [排序算法]:歸并排序(Merge Sort)(遞歸與非遞歸實現(xiàn)詳解)

    [排序算法]:歸并排序(Merge Sort)(遞歸與非遞歸實現(xiàn)詳解)

    ????????歸并排序,是創(chuàng)建在歸并操作上的一種有效的排序算法。算法是采用分治法(Divide and Conquer)的一個非常典型的應用,且各層分治遞歸可以同時進行。歸并排序思路簡單,速度僅次于快速排序,為穩(wěn)定排序算法,一般用于對總體無序,但是各子項相對有序的數(shù)列。

    2024年01月20日
    瀏覽(37)
  • 【數(shù)據(jù)結(jié)構(gòu)】歸并排序的兩種實現(xiàn)方式與計數(shù)排序

    【數(shù)據(jù)結(jié)構(gòu)】歸并排序的兩種實現(xiàn)方式與計數(shù)排序

    前言:在前面我們講了各種常見的排序,今天我們就來對排序部分收個尾,再來對歸并排序通過遞歸和非遞歸的方法進行實現(xiàn),與對計數(shù)排序進行簡單的學習。 ?? 博主CSDN主頁:衛(wèi)衛(wèi)衛(wèi)的個人主頁 ?? ?? 專欄分類:數(shù)據(jù)結(jié)構(gòu) ?? ??代碼倉庫:衛(wèi)衛(wèi)周大胖的學習日記?? ??關(guān)注博

    2024年01月18日
    瀏覽(22)
  • 快速排序的非遞歸實現(xiàn)、歸并排序的遞歸和非遞歸實現(xiàn)、基數(shù)排序、排序算法的時間復雜度

    快速排序的非遞歸實現(xiàn)、歸并排序的遞歸和非遞歸實現(xiàn)、基數(shù)排序、排序算法的時間復雜度

    我們使用一個棧來模擬函數(shù)的遞歸過程,這里就是在利用棧分區(qū)間。把一個區(qū)間分為 [left,keyi-1][key][keyi+1,right]遞歸下去,直至區(qū)間不存在或left right。 如圖所示: 先把整體的區(qū)間壓進去,然后出棧,處理完畢后找到keyi再分為左右兩個區(qū)間。然后往棧里壓有區(qū)間,壓左區(qū)間,就

    2024年02月17日
    瀏覽(24)
  • 【數(shù)據(jù)結(jié)構(gòu)】非遞歸實現(xiàn)快速排序與歸并排序

    【數(shù)據(jù)結(jié)構(gòu)】非遞歸實現(xiàn)快速排序與歸并排序

    遞歸是可以向非遞歸進行變化的: 比如很經(jīng)典的 斐波那契數(shù)列 可以用 遞歸 實現(xiàn)也可以用 循環(huán) 實現(xiàn) 但是有些復雜的遞歸僅僅依靠循環(huán)是很難控制的, 所以我們需要借助數(shù)據(jù)結(jié)構(gòu)中的 棧與隊列 幫助我們用非遞歸模擬遞歸, 故有的時候我們說非遞歸不是遞歸卻勝似遞歸 通過

    2024年01月21日
    瀏覽(32)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】:非遞歸實現(xiàn)快速排序、歸并排序

    【數(shù)據(jù)結(jié)構(gòu)與算法】:非遞歸實現(xiàn)快速排序、歸并排序

    ?? 個人主頁 : Quitecoder ?? 專欄 :數(shù)據(jù)結(jié)構(gòu)與算法 上篇文章我們詳細講解了遞歸版本的快速排序,本篇我們來探究非遞歸實現(xiàn)快速排序和歸并排序 快速排序的非遞歸實現(xiàn)主要依賴于棧(stack)來模擬遞歸過程中的函數(shù)調(diào)用棧。遞歸版本的快速排序通過遞歸調(diào)用自身來處理子

    2024年03月24日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包