C語言排序算法之選擇排序(直接選擇排序,堆排序)
前言
本期為大家?guī)淼氖浅R娕判蛩惴ㄖ械倪x擇排序,主要有直接選擇排序以及——堆排序(有點難理解),包您一看就會,快來試試吧~

一、直接選擇排序
1.1 算法思想
每一次從待排序的數(shù)據元素中選出最小(或最大的)的一個元素,存放在序列的起始位置,直到全部待排序的數(shù)據元素排完。
在元素集合a[i]--a[n-1]中選擇關鍵碼最大(小)的數(shù)據元素 若它不是這組元素中的最后一個(第一個)元素,則將它與這組元素中的最后一個(第一個) 元素交換 在剩余的 [a[i] , a[n-2] …… [a[i+1],a[n-1] ]集合中,重復上述步驟,直到集合剩 余1個元素。
我們拿一組實例來感受一下,直接選擇排序是怎么運算的:

1.2 代碼實現(xiàn)
給大家?guī)硪粋€優(yōu)化版本的直接選擇排序,一次遍歷,選出最大數(shù)和最小數(shù),然后交換,相較于傳統(tǒng)的,效率高了許多。
#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的符號即可實現(xiàn)升序、降序轉換。
}
if (a[i] <a[maxi])
{
maxi = i;
}
}
//交換
Swap(&a[begin],&a[mini]);
//因為還有一種特殊情況,就是begin跟maxi重疊,然后執(zhí)行第一次交換之后,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) ,直接選擇排序不管數(shù)據的順序如何,都要遍歷至結束
- 3.空間復雜度:O(1)
- 4.穩(wěn)定性:不穩(wěn)定
二、堆排序
2.1 什么是堆?

2.2 判斷是否是堆

我們在給到一個數(shù)組的時候,里面的數(shù)據往往不是“堆”,我們在使用堆排序的時候,就需要建堆,
堆排序(Heapsort)是指利用堆積樹(堆)這種數(shù)據結構所設計的一種的排序算法,它是選擇排序的一種,利用堆來進行選擇數(shù)據。跟著我一起看看具體是怎么操作的。
建小堆排降序,建大堆排升序。
怎樣建堆呢?這里我們的前輩就設計了一種算法
2.3 向下調整算法
堆排序的本質是選擇排序
向下調整算法,如果是建小堆(排降序),前提:左右子樹都是小堆。大堆就是反著來。
從根節(jié)點開始,選出左右孩子中小的那一個跟父親比較,如果比父親小就交換,然后繼續(xù)往下調整,調整到葉子節(jié)點就停止。
2.4 自底向上的建堆方式
這種建堆方式是從倒數(shù)第二層的節(jié)點(葉子節(jié)點的上一層)開始,從右往左,從下到上的向下進行調整。

2.5 代碼實現(xiàn)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//打印數(shù)據
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;
}
//向下調整算法
//從根節(jié)點開始,如果是建立小堆選出左右孩子中小的那一個,跟父親比較,如果比父親小就交換
void AdjustDwon(int* a, int n, int root)//建小堆
{
int parent = root;//父親節(jié)點
int child = parent * 2 + 1;//默認是左孩子
while (child < n)//葉子節(jié)點下標不會超過數(shù)組總下標數(shù)n
{
//選出左右孩子中最小的那一個
if (child+1 < n&& a[child + 1] < a[child])
{
child += 1;//用a[child]與父親節(jié)點a[parent]比較
}
if (a[child] < a[parent])
{
//交換,傳地址
Swap(&a[child], &a[parent]);
//交換后,將child,作為根節(jié)點繼續(xù)向下調整,持續(xù)建堆
parent = child;
//新的左孩子
child = parent * 2 + 1;
}
else
{
break;//如果不用交換,直接結束循環(huán)
}
}
}
//堆的建立
//大堆要求:樹中所有的父親都>=孩子,根是最大的
//小堆要求:書中所有的父親都<=孩子,根是最小的
//建大堆排升序,建小堆排降序
//建堆的時間復雜度是O(N);
void HeapSort(int *a,int n)
{
//找父親節(jié)點
for (int i=(n-1-1)/2;i>=0;--i)
{
//向下調整算法
AdjustDwon(a,n,i);
}
//大堆或小堆建立完畢,排序
//用主根節(jié)點與最后一個節(jié)點交換位置
int end = n - 1;
while (end>0)
{
//交換,傳地址
Swap(&a[0],&a[end]);
//繼續(xù)向下調整
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]));
//打印數(shù)據
Printf(a,sizeof(a) / sizeof(a[0]));
return 0;
}
2.6 堆排序的特性總結
- 1.堆排序使用堆來選數(shù),效率高很多
- 2.時間復雜度:O(N*logN)
- 3.空間復雜度:O(1)
- 4.穩(wěn)定性:不穩(wěn)定
2.7 堆排序的特性總結
- 1.堆排序使用堆來選數(shù),效率高很多
- 2.時間復雜度:O(N*logN)
- 3.空間復雜度:O(1)
- 4.穩(wěn)定性:不穩(wěn)定
到此這篇關于C語言排序算法之選擇排序(直接選擇排序,堆排序)的文章就介紹到這了,更多相關C語言選擇排序 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
用c語言實現(xiàn)2000內既能被3整除又能被7整除的個數(shù)
本篇文章是對使用c語言實現(xiàn)2000內既能被3整除又能被7整除的個數(shù),用實例進行了分析說明,需要的朋友參考下2013-05-05

