【选择排序】C语言选择排序--堆排序和直接选择排序

选择排序

基本思想: 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

直接选择排序

  • 在元素集合 arr[0]—ar[n] 中选择关键码最大(最小)的元素。
  • 若它不是这组元素中的最后一个元素(第一个元素),则将它与这组元素中的最后一个(第一个)元素交换。
  • 在剩余的 arr[0]—arr[n-1] 中选择关键码最大(最小)的元素,重复上述步骤,直到集合剩余一个元素。

以数组 int arr[] = { 9, 6, 3, 6, 2, 7, 5, 8, 1 } 举例(升序):
第一步,遍历 arr[0]–arr[8] ,找到最小值的下标min=8,arr[0]与arr[8]值交换
第二步,遍历 arr[1]–arr[8] ,找到最小值的下标min=2,arr[1]与arr[2]值交换

重复上述步骤,直到集合剩余一个元素

代码演示:

int arr[] = { 9, 6, 3, 6, 2, 7, 5, 8, 1 };
     //进行排序 
	for (int i =0;i<sizeof(arr)/sizeof(int)-1;i++)
	{
		int leght = i;//定位最左的未排序的下标
		int min = i;//可移动查找的下标
		int j = i;//最左的未排序的下标随着排序变动
		for (j = leght; j < sizeof(arr) / sizeof(int); j++)
		{
		//找未排序的最小值
			if (arr[min] > arr[j])
			{
				min = j;
			}
		}
		//交换值
		int tmp = arr[min];
		arr[min] = arr[leght];
		arr[leght] = tmp;

	}
	return 0;

这里,对二叉树进行了优化: 遍历一次查询最大值和最小值。感兴趣的同学可以了解下:

int main()
{
	//举例的是特殊形式的数组
	int arr[] = { 9, 6, 3, 6, 2, 7, 5, 8, 1 };
	int leght = 0;
	int right = sizeof(arr)/sizeof(int)-1;
	//排序左侧的数和右侧的数
	while (leght < right)
	{
		//从leght 开始比较
	    int min = leght;
		int max = leght;
		for (int j = leght; j <= right; j++)
		{
			//找最小值的下标
			if (arr[min] > arr[j])
			{
				min = j;
			}
			//找最大值的下标
			if (arr[max] < arr[j])
			{
				max = j;
			}
		}
		//小的值放左侧
		int tmp = arr[min];
		arr[min] = arr[leght];
		arr[leght] = tmp;
		//特殊条件,max==leght,会出现最小值再数组的右边
		if (max == leght)
		{
			max = min;
		}
		//大的值放右侧
		tmp = arr[max];
		arr[max] = arr[right];
		arr[right] = tmp;
		leght++;
		right--;
	}

	return 0;
}

堆排序

堆排序是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是,排升序建大堆,排降序建小堆
堆排序需要具有二叉树的相关知识
未学过二叉树和堆的点击此链接
以数组 int arr[] = { 5, 17, 4, 20, 16, 3 };举例:

  1. 先把数组变成大堆
  2. 把 arr[0] 和 arr[n] 交换值,再用向下调整算法
  3. 把 arr[1] 和 arr[n-1] 交换值,再用向下调整算法

  4. 在这里插入图片描述

代码演示:

//值交换函数
void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int main()
{
	int arr[] = { 5, 17, 4, 20, 16, 3 };
	//在原数组内用向上调整法->大堆
	for (int i = 1; i < sizeof(arr) / sizeof(int); i++)
	{
		int child = i;
		int parent = (i - 1) / 2;
		while (child > 0)
		{
			if (arr[child] > arr[parent])
			{
				Swap(&arr[child], &arr[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
	//排序
	for (int j = sizeof(arr) / sizeof(int) - 1; j > 0; j--)
	{
		//从后往前排,把最大值放数组尾部
		Swap(&arr[0], &arr[j]);
		//向下调算法
		int parent = 0;
		int child = 0 * 2 + 1;//假设左孩子大
		while (child < j)//左孩子要在未排序的范围内
		{
		    //右孩子要在未排序的范围内
			if (child + 1 < j-1 && arr[child] < arr[child+1])
			{
				//假设不成立就换成右孩子
				child++;
			}
			//父子交换值
			if (arr[child] > arr[parent])
			{
				Swap(&arr[child], &arr[parent]);
                //父子换下标
				parent = child;
				child = parent*2 + 1;//继续假设左孩子大
			}
			else
			{
				break;
			}
		}
	}
	return 0;
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值