数据结构中排序算法-选择排序(3)

1,简单选择排序

  • 基本思想:每一趟在n-i+1个记录中选取关键字最小的的记录作为有序序列中的第i个记录。一趟排序的操作为:通过N-i次关键字间的比较,从N-i+1个记录中,找出关键字最小的记录,并将它与第i个记录交换。
  • 主要操作是比较和移动,无论初始序列如何,比较次数不变,都是n(n-1)/2;当初始序列为正序时,移动次数最少为0,当为逆序时,移动次数为最大,为3(n-1)。
  • 时间复杂度:最好,最坏都是O(n^2)。
  • 空间复杂度:O(1)。
  • 不是稳定的排序算法。比如:排序前 2  4  4^ 3。排序后 2  3  4^  4。



      代码如下:

void selectSort(SqList &L){
	int i,j;
	int min;
	int temp;
	int minV;
	for (i=0;i<L.length;i++)
	{
		min=i;
		minV=L.list[i];
	   for(j=i;j<L.length;j++)
		   if(L.list[j]<minV)
		   {
			   min=j;
			   minV=L.list[j];
		   }
	   if(i!=min)
	   {
		   temp=L.list[i];
		   L.list[i]=L.list[min];
		   L.list[min]=temp;
	   }
	}
}

void main()
{ 
	SqList St;
	printf("***********************************************\n");
	printf("               简单选择排序算法                    \n");
	printf("***********************************************\n");
	printf("请输入需要排序的关键字个数N (N<%d):",MAXSIZE);
	scanf("%d",&St.length);
	printf("\n");
	printf("请输入%d个待排序的关键字:\n",St.length);
	for (int i=0;i<St.length;i++)
		scanf("%d",&St.list[i]);
	selectSort(St);
	printf("\n");
	printf("输出排序结果:");
	for(int j=0;j<St.length;j++)
		printf("%d ",St.list[j]);
	printf("\n");
	printf("\n");
}

运行结果如下:



2,堆排序

  • 基本思想:堆对应的一维数组可以看做是一个完全二叉树,所有非终端的结点的值均不大于(或不小于)其左右孩子结点的值。那么,输出根结点的值一定是最小的元素,再将剩下的n-1个元素调整为堆,再输出根结点,为第二小的元素,如此反复,最终输出的序列就是有序的序列。
  • 堆排序有两个问题需要解决:(1),如何将一个无序序列建成一个堆(建初始堆)。(2),如何在输出堆顶后,调整剩下的元素,使之重新成为一个新堆(筛选)。
  • 筛选:输出堆顶元素后,将堆中最后一个元素代替输出的堆顶元素,但是此时,已破坏了堆的特性了, 将该元素与左右子树的根结点比较,选出最小的子树根结点并与之交换,若交换后,破坏了子树的堆特性 ,继续向下调整,选出最小子树的根结点并与之交换,直到到叶子结点为止。筛选是自上而下的调整
  • 建初始堆:将一个具有n个元素的无序数组序列看成是一个完全二叉树,从 最后一个非终端结点(不大于n/2的最大整数这个结点)开始向上调整,使每棵子树满足堆的特性,直到根结点。建初始堆是自下而上的调整。
  • 时间复杂度:最好最坏都是O(nlogn),想比快速排序来说,这是堆排序最大的优点。
  • 空间复杂度:O(1)。
  • 不是稳定的排序算法。
  • 适合N很大的排序序列
  • 对初始序列不敏感。  

            代码如下:

#include "stdafx.h"
#include<stdio.h>
#define MAXSIZE 40

struct SqList{
	int list[MAXSIZE+1];
	int length;
};
/*
此函数的功能是:对于序列[s……m],除L.list[s]这个元素外,剩余元素都满足堆的定义
                对这个元素进行进行调整,使之满足堆的定义。另外,此堆是个大顶堆,
				即所有非终端结点的值均大于或等于其左右孩子的结点的值。
建大顶堆而不是小顶堆的原因:我们排序最终的结果是要使序列呈非递减排列,也就是最终要使
第一个元素为最小的,最后一个元素为最大的,那么建大顶堆,最大元素再第一个,通过与最后
一个元素交换,就变成了最后一个,也就是说每次使最大的元素成为堆顶,再与没有被交换过的
最后一个元素交,当交换到只剩一个元素时,序列也就呈非递减状态了。
变量s:待调整的元素序号。
变量m;序列的长度
*/
void HeapAdjust(SqList&L,int s,int m)
{
	int i;
	int rc=L.list[s];//暂时保存待调整元素
	for(i=2*s;i<=m;i*=2)//为什么有等于号?因为需要向下调整到叶子结点,i=m,代表s这个结点只有左叶子结点,小于代表有左右叶子结点
	{
		if(i<m&&L.list[i]<L.list[i+1])//为什么是i<m而不是i<=m呢?当i=m时,只有左叶子结点,所以没法比较左右结点值的大小,
			++i;                      //也就是说必须保证s这个结点的左右孩子结点同时存在。
		if(rc>=L.list[i])             //如果待调整的值大于或等于找到的结点的值,则无需向下调整了。
			break;
		L.list[s]=L.list[i];          //将孩子结点的值向上移动到s结点(父结点)
		s=i;                          //同时继续向下调整。
	}
	L.list[s]=rc;                     //将待调整的元素rc放在找到的最终位置上
}

void HeapSort(SqList &L){
	int i,j;
	for(i=L.length/2;i>0;i--)        //对于无序序列的待排元素,从中间向前每个元素开始调整,建立大顶堆。
		HeapAdjust(L,i,L.length);
	for(j=L.length;j>1;j--)          //将堆顶元素和最后一个元素交换,同时将指向最后一个元素的位置前移,再进行调整。
	{
		L.list[0]=L.list[j];
	    L.list[j]=L.list[1];
		L.list[1]=L.list[0];
		HeapAdjust(L,1,j-1);
	}

}

void main()
{ 
	SqList St;
	printf("***********************************************\n");
	printf("               堆排序算法                    \n");
	printf("***********************************************\n");
	printf("请输入需要排序的关键字个数N (N<%d):",MAXSIZE);
	scanf("%d",&St.length);
	printf("\n");
	printf("请第一个数输入0,为暂存单元,再输入%d个待排序的关键字值:\n",St.length);
	for (int i=0;i<=St.length;i++)
		scanf("%d",&St.list[i]);
	HeapSort(St);
	printf("\n");
	printf("输出排序结果:");
	for(int j=1;j<=St.length;j++)
		printf("%d ",St.list[j]);
	printf("\n");
	printf("\n");
}


运行结果如下:








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值