首頁 > 軟體

C語言排序演演算法之選擇排序(直接選擇排序,堆排序)

2022-07-14 14:04:18

前言

本期為大家帶來的是常見排序演演算法中的選擇排序,主要有直接選擇排序以及——堆排序(有點難理解),包您一看就會,快來試試吧~

一、直接選擇排序

1.1 演演算法思想

每一次從待排序的資料元素中選出最小(或最大的)的一個元素,存放在序列的起始位置,直到全部待排序的資料元素排完。

在元素集合a[i]--a[n-1]中選擇關鍵碼最大(小)的資料元素 若它不是這組元素中的最後一個(第一個)元素,則將它與這組元素中的最後一個(第一個) 元素交換 在剩餘的 [a[i] , a[n-2] …… [a[i+1],a[n-1] ]集合中,重複上述步驟,直到集合剩 餘1個元素。

我們拿一組範例來感受一下,直接選擇排序是怎麼運算的:

1.2 程式碼實現

給大家帶來一個優化版本的直接選擇排序,一次遍歷,選出最大數和最小數,然後交換,相較於傳統的,效率高了許多。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
 
//交換
void Swap(int* mini, int* maxi)
{
	int tmp = *mini;
	*mini = *maxi;
	*maxi = tmp;
}
 
//列印
void Print(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}
 
//直接選擇排序
void SelectSort(int *a,int n)
{
	//下標
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin, maxi = end;
		//選出最大的給maxi,選出最小的給mini
		for (int i=begin;i<=end;++i)
		{
			if (a[i]>a[mini])//升序
			{
				mini = i;   //改兩個if的符號即可實現升序、降序轉換。
			}
			if (a[i] <a[maxi])
			{
				maxi = i;
			}
		}
		//交換
		Swap(&a[begin],&a[mini]);
        //因為還有一種特殊情況,就是begin跟maxi重疊,然後執行第一次交換之後,maxi記錄的是最小值
        if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		++begin;
		--end;
	}
}
直接選擇排序
//void SelectSort(int* a, int n)//(升序)
//{
//	for (int j=0;j<n-1;j++)//整體遍歷
//	{
//		for (int i=j+1;i<n;i++)//遍歷比較
//		{
//			if (a[j] > a[i])//比較交換
//			{
//				int tmp = a[j];
//				a[j] = a[i];
//				a[i] = tmp;
//			}
//		}
//	}
//}
int main()
{
	int a[10] = { 3,5,9,7,4,2,1,6,0,8 };
	SelectSort(a, sizeof(a) / sizeof(a[0]));
	//列印
	Print(a, sizeof(a) / sizeof(a[0]));
	return 0;
}

1.3 直接選擇排序的特徵總結

  • 1.直接選擇排序的演演算法非常好理解,但是效率不高,實際中也很少使用
  • 2.時間複雜度:O(N^2) ,直接選擇排序不管資料的順序如何,都要遍歷至結束
  • 3.空間複雜度:O(1)
  • 4.穩定性:不穩定

二、堆排序

2.1 什麼是堆?

2.2 判斷是否是堆

我們在給到一個陣列的時候,裡面的資料往往不是“堆”,我們在使用堆排序的時候,就需要建堆,

堆排序(Heapsort)是指利用堆積樹(堆)這種資料結構所設計的一種的排序演演算法,它是選擇排序的一種,利用堆來進行選擇資料。跟著我一起看看具體是怎麼操作的。

建小堆排降序,建大堆排升序。

怎樣建堆呢?這裡我們的前輩就設計了一種演演算法

2.3 向下調整演演算法

 堆排序的本質是選擇排序

向下調整演演算法,如果是建小堆(排降序),前提:左右子樹都是小堆。大堆就是反著來。

從根節點開始,選出左右孩子中小的那一個跟父親比較,如果比父親小就交換,然後繼續往下調整,調整到葉子節點就停止。

2.4 自底向上的建堆方式

這種建堆方式是從倒數第二層的節點(葉子節點的上一層)開始,從右往左,從下到上的向下進行調整。

2.5 程式碼實現

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//列印資料
void Printf(int* a, int n)
{
	for (int i = 0; i < n; ++i)
	{
		printf("%d ", a[i]);
	}
}
 
//交換,傳地址
void Swap(int* child, int* parent)
{
	int tmp = *child;
	*child = *parent;
	*parent = tmp;
}
//向下調整演演算法
//從根節點開始,如果是建立小堆選出左右孩子中小的那一個,跟父親比較,如果比父親小就交換
void AdjustDwon(int* a, int n, int root)//建小堆
{
	int parent = root;//父親節點
	int child = parent * 2 + 1;//預設是左孩子
	while (child < n)//葉子節點下標不會超過陣列總下標數n
	{
		//選出左右孩子中最小的那一個
		if (child+1 < n&& a[child + 1] < a[child])
		{
			child += 1;//用a[child]與父親節點a[parent]比較
		}
		if (a[child] < a[parent])
		{
			//交換,傳地址
			Swap(&a[child], &a[parent]);
			//交換後,將child,作為根節點繼續向下調整,持續建堆
			parent = child;
			//新的左孩子
			child = parent * 2 + 1;
		}
		else
		{
			break;//如果不用交換,直接結束迴圈
		}
	}
}
//堆的建立
//大堆要求:樹中所有的父親都>=孩子,根是最大的
//小堆要求:書中所有的父親都<=孩子,根是最小的
//建大堆排升序,建小堆排降序
//建堆的時間複雜度是O(N);
void HeapSort(int *a,int n)
{
	//找父親節點
	for (int i=(n-1-1)/2;i>=0;--i)
	{
		//向下調整演演算法
		AdjustDwon(a,n,i);
	}
    //大堆或小堆建立完畢,排序
	//用主根節點與最後一個節點交換位置
	int end = n - 1;
	while (end>0)
	{
		//交換,傳地址
		Swap(&a[0],&a[end]);
		//繼續向下調整
		AdjustDwon(a,end,0);
		--end;
	}
}
//選擇排序—堆排序
int main()
{
	int a[10] = {9,2,5,4,3,1,6,7,8,0};
	//堆的建立
	HeapSort(a,sizeof(a) / sizeof(a[0]));
	//列印資料
	Printf(a,sizeof(a) / sizeof(a[0]));
	return 0;
}

2.6 堆排序的特性總結

  • 1.堆排序使用堆來選數,效率高很多
  • 2.時間複雜度:O(N*logN)
  • 3.空間複雜度:O(1)
  • 4.穩定性:不穩定

2.7 堆排序的特性總結

  • 1.堆排序使用堆來選數,效率高很多
  • 2.時間複雜度:O(N*logN)
  • 3.空間複雜度:O(1)
  • 4.穩定性:不穩定

到此這篇關於C語言排序演演算法之選擇排序(直接選擇排序,堆排序)的文章就介紹到這了,更多相關C語言選擇排序 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com