提示:本文是为C语言排序算法小萌新科普的,学习其他语言的朋友可以参考,大佬“非礼勿视”。
但是欢迎各位大佬萌捧场和对笔者进行教导,对本文及笔者提出建议或意见。
文章目录
前言
提示:选择排序法是一种不稳定的排序算法,但是他有升级版。
提示:以下是本篇文章正文内容
一、选择排序是什么?
概念释义
选择排序是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
理论理解
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
二、使用步骤
1.核心函数
核心函数如下(示例):
void swap(int *a,int *b) //交换两个数
{
int temp = *a;
*a = *b;
*b = temp;
}
void selection_sort(int arr[], int len)
{
int i,j;
for (i = 0 ; i < len - 1 ; i++)
{
int min = i;
for (j = i + 1; j < len; j++) //寻找未排序的元素
if (arr[j] < arr[min]) //找到目前最小值
min = j; //记录最小值
swap(&arr[min], &arr[i]); //做交换
}
}
2.实现代码【精简版】
代码如下(示例):
#include <stdio.h>
int main()
{
int i,j,t,a[11]; //定义变量及数组为基本整型
printf("请输入10个数:\n");
for(i=1;i<11;i++)
scanf("%d",&a[i]); //从键盘中输入要排序的10个数字
for(i=1;i<=9;i++)
for (j=i+1;j<=10;j++)
if(a[i]>a[j]) //如果前一个数比后一个数大,则利用中间变量t实现两值互换
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
printf("排序后的顺序是:\n");
for(i=1;i<=10;i++)
printf("%5d", a[i]); //输出排序后的数组
printf("\n");
return 0;
}
程序中用到两个 for 循环语句:
第一个 for 循环是确定位置的,该位置是存放每次从待排序数列中经选择和交换后所选出的最小数。
第二个 for 循环是实现将确定位置上的数与后面待排序区间中的数进行比较的。

3.函数优化
同时找最大值和最小值,然后把最大值放到末尾,最小值放到开始。
优化版本同时找最小值和最大值放到起始和末尾,并依次找之,直到无逆序情况。
优化如下(示例)
void SelectionSort_P(int arr[],size_t size)
{
int left = 0;
int right = size - 1;
int max = left;
int min = right;
while (left < right)
{
max = left;
min = right;
for (int i = left; i <= right;++ i)
{
if (arr[max] < arr[i])
max = i;
if (arr[min] > arr[i])
min = i;
}
//处理特殊情况
std::swap(arr[left], arr[min]);
if (left == max)
max = min;
std::swap(arr[max], arr[right]);
left++;
right--;
}
}
三、代码升级
1.一次升级(树形选择排序)
名词释义
树形选择排序又称锦标赛排序,是一种按照锦标赛的思想进行选择排序的方法。首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出最小的记录为止。
核心代码
代码如下(示例):
int a;
if ( n % 2 == 0 )
{
a = n / 2;
}else {
a = (n + 1) / 2;
}
int rt[a];
if ( n % 2 == 0 )
{
int t = 0;
for ( int i = 0; i < n; i += 2 )
{
rt [t] = MAX( num[i], num[i + 1] );
t++;
}
}else {
int t = 0;
for ( int i = 0; i < n; i += 2 )
{
if ( n - 1 == i )
{
rt[t] = num[i];
}else {
rt [t] = MAX( num[i], num[i + 1] );
}
t++;
}
}
程序雏形
本程序只进行了一次排序,作为演示(好吧,其实是第一次排序的第一次筛选)
代码如下(示例):
#include <stdio.h>
#include <stdlib.h>
#define MAX( a, b ) ( (a) > (b) ? (a) : (b) )
int main()
{
/* 定义一个长度未知的数组 */
int n;
int *num;
printf( "数据个数:" );
scanf( "%d", &n );
num = (int *) malloc( n * sizeof(int) );
printf( "请输入数据:" );
for ( int i = 0; i < n; i++ )
{
scanf( "%d", &num[i] );
}
/*进行排序*/
int a;
if ( n % 2 == 0 )
{
a = n / 2;
}else {
a = (n + 1) / 2;
}
int rt[a];
if ( n % 2 == 0 )
{
int t = 0;
for ( int i = 0; i < n; i += 2 )
{
rt [t] = MAX( num[i], num[i + 1] );
t++;
}
}else {
int t = 0;
for ( int i = 0; i < n; i += 2 )
{
if ( n - 1 == i )
{
rt[t] = num[i];
}else {
rt [t] = MAX( num[i], num[i + 1] );
}
t++;
}
}
printf( "结果:" );
for ( int i = 0; i < a; i++ )
{
printf( "%d ", rt[i] );
}
}
完整程序
代码如下(示例):
Nocode
因为完整程序过长,而且笔者在初二攻读学业,所以没有时间去完成那么大的工程量,在这偷个懒。
如果这篇文章点赞过15个或者浏览量过1500人次,我会考虑再写一篇文章来贴出完整程序并且带有完整注释 。
2.二次升级(堆排序)
名词释义
堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
理论理解
把待排序的元素按照大小在二叉树位置上排列(使用数组模拟,没必要一定使用二叉树),排序好的元素要满足:父节点的元素要大于等于其子节点;这个过程叫做堆化过程,如果根节点存放的是最大的数,则叫做大根堆;如果是最小的数,自然就叫做小根堆了。
根据这个特性(大根堆根最大,小根堆根最小),就可以把根节点拿出来,然后再堆化下,再把根节点拿出来,一直循环到最后一个节点,结束排序。
先排序好子树的顺序,然后再一步步往上,到排序根节点上。然后又相反(因为根节点也可能是很小的)的,从根节点往子树上排序。最后才能把所有元素排序好
核心代码
代码如下(示例):
void max_heapify(int arr[], int start, int end)
{
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end) //若子节点指标在范围内才做比较
{
if (son + 1 <= end && arr[son] < arr[son + 1])
//先比较两个子节点大小,选择最大的
son++;
if (arr[dad] > arr[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
return;
else //否则交换父子内容再继续子节点和孙节点比较
{
swap(&arr[dad], &arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
完整程序
代码如下(示例):
#include <stdio.h>
#include <stdlib.h>
void swap(int* a, int* b)
{
int temp = *b;
*b = *a;
*a = temp;
}
void max_heapify(int arr[], int start, int end)
{
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end) //若子节点指标在范围内才做比较
{
if (son + 1 <= end && arr[son] < arr[son + 1])
//先比较两个子节点大小,选择最大的
son++;
if (arr[dad] > arr[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
return;
else //否则交换父子内容再继续子节点和孙节点比较
{
swap(&arr[dad], &arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void heap_sort(int arr[], int len)
{
int i;
//初始化,i从最後一个父节点开始调整
for (i = len / 2 - 1; i >= 0; i--)
max_heapify(arr, i, len - 1);
//先将第一个元素和已排好元素前一位做交换,再重新调整,直到排序完毕
for (i = len - 1; i > 0; i--)
{
swap(&arr[0], &arr[i]);
max_heapify(arr, 0, i - 1);
}
}
int main() {
int arr[] = {
3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
int len = (int) sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
int i;
for (i = 0; i < len; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
总结
总结…嗯……
没有什么要总结的。如果有,那就是:时代在进步,代码在升级,唯有C语言一成不变的美丽,独领风骚。