最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C語言快速排序三種方法的單趟實現(xiàn)

 更新時間:2022年06月13日 11:44:02   作者:沙漠下的胡楊  
本文將通過圖片重點為大家介紹一下C語言中快速排序三種方法的單趟實現(xiàn):分別是hoare法、挖坑法、雙指針法,文中示例代碼講解詳細,感興趣的可以了解一下

交換排序的思想

基本思想:所謂交換,就是根據(jù)序列中兩個記錄鍵值的比較結(jié)果來對換這兩個記錄在序列中的位置,交換排 序的特點是:將鍵值較大的記錄向序列的尾部移動,鍵值較小的記錄向序列的前部移動。

冒泡排序的思想

冒泡排序比較簡單,我們之前使用也很多,簡單講解,就是比較兩個數(shù),如果比他大就交換,沒有他大就接著向后比,一直到數(shù)組結(jié)束,這是單趟排序,多趟就是控制好下標,進行循環(huán)即可。

冒泡代碼實現(xiàn)

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
 
 
void BubbleSort(int* a, int n)
{
	assert(a);
 
	for (int j = 0; j < n - 1; ++j)
	{
		int exchange = 0;//定義變量,用于判斷是否交換過
		for (int i = 1; i < n - j; ++i)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}
 
		if (exchange == 0)//沒有交換過表示有序,直接跳出
		{
			break;
		}
	}
}

冒泡排序的特性

1. 冒泡排序是一種非常容易理解的排序

2. 時間復雜度:O(N^2)

3. 空間復雜度:O(1)

4. 穩(wěn)定性:穩(wěn)定

快速排序的整體框架

快速排序是Hoare于1962年提出的一種二叉樹結(jié)構(gòu)的交換排序方法,其基本思想為:任取待排序元素序列中 的某元素作為基準值,按照該排序碼將待排序集合分割成兩子序列,左子序列中所有元素均小于基準值,右 子序列中所有元素均大于基準值,然后最左右子序列重復該過程,直到所有元素都排列在相應位置上為止。

// 假設(shè)按照升序?qū)rray數(shù)組中[left, right)區(qū)間中的元素進行排序
void QuickSort(int array[], int left, int right)
{
 if(right - left <= 1)
 return;
 
 // 按照基準值對array數(shù)組的 [left, right)區(qū)間中的元素進行劃分
 int div = partion(array, left, right);
 
 // 劃分成功后以div為邊界形成了左右兩部分 [left, div) 和 [div+1, right)
 // 遞歸排[left, div)
 QuickSort(array, left, div);
 
 // 遞歸排[div+1, right)
 QuickSort(array, div+1, right);
}

述為快速排序遞歸實現(xiàn)的主框架,發(fā)現(xiàn)與二叉樹前序遍歷規(guī)則非常像,同學們在寫遞歸框架時可想想二叉 樹前序遍歷規(guī)則即可快速寫出來,后序只需分析如何按照基準值來對區(qū)間中數(shù)據(jù)進行劃分的方式即可。

簡單理解:

我們先選出一個數(shù),然后把所有數(shù)據(jù)分為三部分,第一部分是大于這個數(shù)的部分,第二個部分是這個數(shù),第三個部分是大于這個數(shù)的。

然后,進行遞歸求解,對于小于的部分,選一個數(shù),分為三部分。對于大于的部分,選一個數(shù),分為三部分進行求解。

遞歸返回條件:首先是區(qū)間不存在返回,區(qū)間只有一個數(shù)返回。

快速排序單趟實現(xiàn)邏輯

1. hoare版本單趟實現(xiàn)(左右指針法)

首先我們先學習下最經(jīng)典的左右指針法:

首先我們一般都會這兩個疑問?(后續(xù)挖坑法和前后指針法同理)

1.為什么要選左邊的數(shù)作為初識位置比較位置。

2.為什么要讓右邊先走?

我們之所以選取左邊,只是因為方便,容易控制,你也可以選擇右邊,或者任意位置,都可以,只不過在代碼邏輯上稍微復雜點,不容易控制。

我們讓右邊先走,是因為最后我們要把 key位置的數(shù)據(jù)移動到相遇位置,也就是key位置數(shù)據(jù)的正確位置,所以我們應該保證讓左邊來遇到右邊,就是讓右邊的位置先到等著左邊。因為我們選取的是左邊的key,所以左邊的下標就是少了 1 ,我們讓右邊先走就可以剛好彌補過來。反之,如果我們選取左邊為key,還讓左邊先走,那么我們最后就會發(fā)現(xiàn),這個位置的下標就錯了,不能保證左邊都是大于key的數(shù)了。

綜上:我們?nèi)绻x擇了左邊為key,那么就讓右邊先走,選擇右邊為key,就讓左邊先走。

我們看著示意圖實現(xiàn)下單趟排序代碼:

//前后指針法單趟排序
int PartSort(int *a,int left,int right)
{
	int keyi = left;//先保存最左側(cè)下標,作為keyi
 
	while (left < right)
	{
		//先讓右走,找小,并且不能越界
		while (left < right && a[right] >= a[keyi])
		{
			--right;
		}
 
		//再讓左走,找大,不越界。
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}
 
		//交換左邊大的,和右邊小的
		Swap(&a[left], &a[right]);
	}
 
	//循環(huán)完成,我們在最后交換下,相遇位置的和原來keyi位置的值
	Swap(&a[keyi], &a[left]);
 
	//返回相遇位置的下標是為進行下一步遞歸。
	return left;
}

2.挖坑法單趟排序?qū)崿F(xiàn)

我們看下有點意思的挖坑法。

我們觀察發(fā)現(xiàn),還是先選取一個位置作為我們比較的數(shù)同時也是坑位,然后還是先讓右邊走,然后把數(shù)據(jù)放到坑中,形成一個新的坑,接著左邊走,再把數(shù)據(jù)放入坑中,形成新坑,最后,把我們選取位置的數(shù)據(jù)放到最后一個坑位上,就滿了。

其實在我們調(diào)試發(fā)現(xiàn),"挖坑" 只不過是形象描述了,其實乜有坑位,只是數(shù)據(jù)重復,然后替換掉了。

圖示比較簡單,我們嘗試實現(xiàn)下單趟排序:

 //挖坑法
int PartSort2(int* a, int left, int right)
{
	int key = a[left];//保存最左邊初始位置的值
 
	while (left < right)
	{
		while (left < right && a[right] >= key)
		{
			--right;
		}
 
		a[left] = a[right];//產(chǎn)生一個坑位
 
		while (left < right && a[left] <= key)
		{
			++left;
		}
 
		a[right] = a[left];//上一個坑位填上,產(chǎn)生新的坑位
	}
 
	a[left] = key;//把最后的坑位填上了。
 
	return left;//返回最后相遇的下標,以便后序遞歸
}

3.前后指針法

前后指針法和左右指針類似但是不完全一樣哦。

前后指針法,其實就是定義兩個指針,一個是prev為初始位置,一個是cur為初始位置+1,cur是遇見大于初始位置的值停下,交換(prev+1)下標的值,直到 cur 指針走到結(jié)尾,此時就交換prev指針和初始位置即可。

簡單理解:

前后指針,就是不停的把大于初始位置的數(shù)據(jù)向后移動,最后一個指針走到末尾了,另一個指針此時的指向,剛好就是我們初始位置在整個數(shù)據(jù)中要排的位置。

需要注意的是:我們每次交換的都是prev+1的下標值,如果 prev = cur 時,此時我們不用交換,prev也不用++,只需要 cur++ 即可。

前后指針的單趟代碼實現(xiàn):

//前后指針法
int PartSort3(int *a, int left, int right)
{
	int prev = left;//后指針
	int cur = left + 1;//前指針
	int keyi = left;//初始位置
 
	while(cur <= right)//當cur小于等于最右邊時進入循環(huán)
	{
		//當cur找到比初始位置大的數(shù),如果此時cur不等于prev,
		//那么就交換cur和++prev,一定是前置++。
		if (a[cur] < a[keyi] && prev != cur)
		{
			Swap(&a[cur], &a[++prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);//最后交換prev和初始位置即可
 
	return prev;//返回prev為了后續(xù)遞歸做鋪墊
}

以上就是詳解C語言快速排序三種方法的單趟實現(xiàn)的詳細內(nèi)容,更多關(guān)于C語言快速排序單趟實現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言深入分析整形數(shù)據(jù)存儲

    C語言深入分析整形數(shù)據(jù)存儲

    C語言中,我們經(jīng)常使用數(shù)據(jù)類型,那么整形數(shù)據(jù)在內(nèi)存中如何存儲?存儲方式是什么?如果你對這些內(nèi)容不太了解的話,相信看完這篇博客后,你會對整形數(shù)據(jù)的存儲有一個新的認識。話不多說,我們進入正題
    2022-08-08
  • C語言中雙向鏈表和雙向循環(huán)鏈表詳解

    C語言中雙向鏈表和雙向循環(huán)鏈表詳解

    這篇文章主要介紹了C語言中雙向鏈表和雙向循環(huán)鏈表詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C++實現(xiàn)LeetCode(147.鏈表插入排序)

    C++實現(xiàn)LeetCode(147.鏈表插入排序)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(147.鏈表插入排序),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù))

    C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù))

    這篇文章主要介紹了C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C++模板編程特性之移動語義

    C++模板編程特性之移動語義

    首先,移動語義和完美轉(zhuǎn)發(fā)這兩個概念是在C++的模板編程的基礎(chǔ)上,新增的特性,主要是配合模板來使用。本篇會從C++的值類型,到移動拷貝與移動賦值來理解移動語義與完美轉(zhuǎn)發(fā)
    2022-08-08
  • C++項目開發(fā)實現(xiàn)圖書管理系統(tǒng)

    C++項目開發(fā)實現(xiàn)圖書管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C++項目開發(fā)實現(xiàn)圖書管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++ 中const修飾虛函數(shù)實例詳解

    C++ 中const修飾虛函數(shù)實例詳解

    這篇文章主要介紹了C++ 中const修飾虛函數(shù)實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C++實現(xiàn)簡單的信息管理系統(tǒng)

    C++實現(xiàn)簡單的信息管理系統(tǒng)

    這篇文章主要為大家介紹了C++實現(xiàn)簡單的信息管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-04-04
  • C++使用宏實現(xiàn)動態(tài)庫加載

    C++使用宏實現(xiàn)動態(tài)庫加載

    開發(fā)的時候,有些項目不能靜態(tài)鏈接動態(tài)庫,需要程序運行時加載動態(tài)庫。本文將使用宏來實現(xiàn)動態(tài)庫的加載,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C++中關(guān)于委派(Delegates)的實現(xiàn)示例

    C++中關(guān)于委派(Delegates)的實現(xiàn)示例

    這篇文章主要介紹了C++中關(guān)于委派(Delegates)的實現(xiàn)示例,針對C++11的一些新特性進行講解,需要的朋友可以參考下
    2015-07-07

最新評論

桂东县| 长寿区| 奉化市| 读书| 湘潭县| 东丰县| 阳西县| 隆德县| 安阳县| 东安县| 乐陵市| 万宁市| 临颍县| 西盟| 商丘市| 泉州市| 凤山市| 仁布县| 花垣县| 临清市| 潮安县| 册亨县| 贡山| 甘南县| 永春县| 封丘县| 东源县| 抚州市| 南川市| 新建县| 达拉特旗| 弥渡县| 清涧县| 南康市| 濉溪县| 隆安县| 南部县| 十堰市| 兴安县| 阳新县| 株洲市|