选择排序算法-C语言实现详解及其升级学习

提示:本文是为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语言一成不变的美丽,独领风骚。

猜你喜欢

转载自blog.csdn.net/m0_56401749/article/details/115118987