热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

排序算法(1):简单选择排序和堆排序

1.简单选择排序(1)本质:每一趟从给定待排序序列A[1n],选择出第i小元素,并和A[i]交换。代码:*****************

1.简单选择排序

(1)本质:每一趟给定待排序序列A[ 1......n ] ,选择出第i小元素,并和A[i]交换。

代码:

/*************************************************
算法:简单选择排序(升序)
时间复杂度为O(n^2)
**************************************************/
void simpleSelectSort(int *arr , int len)
{
	for(int i =0;i运行结果: 
 



(2)性能分析

     简单选择排序记录移动操作次数较少,这点优于冒泡排序。有两层循环,所以时间复杂度为O(n^2)

2.堆排序

2.1 堆的定义

      n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆。

  情形1:ki <= k2i 且ki <= k2i+1 最小化堆小顶堆

  情形2:ki >= k2i 且ki >= k2i+1 最大化堆大顶堆

  其中i=1,2,…,n/2向下取整;


2.2 堆排序(以大顶堆为例,根节点从0开始)

     输出堆顶最大值之后,使得剩余n-1个元素的序列重建一个堆;如此反复执行,便能得到一个有序序列,这个过程称之为堆排序。(升序---大顶堆,降序---小顶堆)


(1)堆的存储

 一般用数组来表示堆,若根结点存在序号0处, i结点的父结点下标就为(i-1)/2。i结点的左右子结点下标分别为2*i+12*i+2

  (注:如果根结点是从1开始,则左右孩子结点分别是2i和2i+1。)

最大化堆如下:

实现堆排序需要解决两个问题:

    1.如何由一个无序序列建成一个堆?

    2.如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?


问题2: 一般在输出堆顶元素之后,视为将这个元素排除,然后用表中最后一个元素填补它的位置,自上向下进行调整:首先将堆顶元素和它的左右子树的根结点进行比较,把最大的元素交换到堆顶;然后顺着被破坏的路径一路调整下去,直至叶子结点,就得到新的堆。自堆顶至叶子的调整过程为"筛选"过程。无序序列建立堆的过程就是一个反复"筛选"过程。

帅选过程代码:

/****************************************************
堆排序是一种选择排序;在最坏的情况下,其时间复杂度也为O(nlogn)
其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上
****************************************************/
/*
函数功能:当堆的某一个节点破坏了堆的性质,调用此函数进行调整剩余的元素,使其为新堆
k      :k节点破坏了堆的性质
*/
void maxHeap(int *arr,int len,int k)
{
	//递归边界条件
	if (k>len/2-1)   //最后一个非叶子节点的下标为len/2-1;
	{
		return;
	}
	//1.比较k节点左右孩子的值,找出左右孩子的较大值
	int i=0;  
	//因为假设根结点的序号为0而不是1,所以i结点左孩子和右孩子分别为2i+1和2i+2
	if ((2*k+2<=len-1)&&arr[2*k+1] 
 

问题1:构建初始堆

     构建堆就是对所有的非叶子节点进行筛选。最后一个非叶子节点的下标为([n/2]-1),所以筛选只需从([n/2]-1)节点开始,自下向上的进行调整,直到堆顶。

/*****************************************************************************
1.给定一个数组,首先根据该数组元素构造一个完全二叉树。
2.从最后一个非叶子结点开始,每次都是从父结点、左孩子、右孩子中进行比较交换;
3.交换可能会引起孩子结点不满足堆的性质,所以每次交换之后需要重新对被交换的孩子结点进行调整。
最后一个非叶子节点下标:[n/2]-1 (根节点的下标为0), n表示节点个数
******************************************************************************/
void createHeap(int *arr , int len)
{
	//最大堆----------自下向上调整,数组的下标从0开始
	for (int i=len/2-1;i>=0;i--)
	{
		maxHeap(arr,len,i);
	}
}

(3)堆排序

     首先输出堆顶元素(因为它是最值),将堆顶元素和最后一个元素交换,这样,第n个位置(即最后一个位置)作为有序区,前n-1个位置仍是无序区,对无序区进行调整,得到堆之后,再交换堆顶和最后一个元素,这样有序区长度变为2。不断进行此操作,将剩下的元素重新调整为堆,然后输出堆顶元素到有序区。每次交换都导致无序区-1,有序区+1。不断重复此过程直到有序区长度增长为n-1,排序完成。

void heapSort(int *arr , int len)
{
	//1. 构建堆
	createHeap(arr,len);
	//2.堆排序
	for (int i=0;i 
 

(4)反思堆排序

     仔细回想一下筛选法调整堆的过程我们发现,第i次调整堆,其实就是把A中的第i大元素放到首位置A[0],然后A[0]和A[n-i-1]互换.这样A[(n-i-1)...n]就已经有序,于是又把A[0...n-i-2]看成一个堆再进行排序,如此重复。调整堆不就是选择出待排序序列中的最大值吗?所以堆排序的本质和选择排序的本质是一样的。选择一个待排序序列中的最小(大)值,这就是选择排序的本质。所以,堆排序是一种选择排序。

(5)性能分析

    堆排序时间=建堆时间+调整堆时间。从上文中知道建堆时间复杂度为O(n*log2n)。筛选法调整堆(maxHeap函数)时间O(log2n),总共循环了n-1次maxHeap函数,所以调整堆时间复杂度为O(n*log2n)。得出堆排序时间复杂度O(n*log2n)。且在最坏情况下时间复杂度也是O(n*log2n)。此外堆排序是不稳定的原地排序算法。


(6)测试代码
void test()
{
	int arr[]={16,20,8,7,17,3,30,1,51,9,6};
	int len = sizeof(arr)/sizeof(int);
	cout<<"排序前:";
	printArr(arr,len);
	cout< 
 
附件:辅助函数
void swap(int *p,int *q)
{
	int tmp;
	tmp =*p;
	*p = *q;
	*q = tmp;
}
void printArr(int *arr,int len)
{
	for (int i=0;i 
 



推荐阅读
  • 本文介绍了Memcached分布式集群中的取模算法和一致性哈希算法的原理及其对缓存命中率的影响。通过详细分析,探讨了如何优化这些算法以提高系统的稳定性和性能。 ... [详细]
  • 单片机编程为何偏爱C语言
    尽管现代有许多高级编程语言如Java、Python等,但单片机编程依然广泛使用C语言。本文将探讨C语言在单片机编程中的优势及其原因。 ... [详细]
  • 非计算机专业的朋友如何拿下多个Offer
    大家好,我是归辰。秋招结束后,我已顺利入职,并应公子龙的邀请,分享一些秋招面试的心得体会,希望能帮助到学弟学妹们,让他们在未来的面试中更加顺利。 ... [详细]
  • PHP实现汉诺塔算法
    昨天研究了一天汉诺塔算法都没搞懂,感觉自己智商被碾压了,还不如《猩球崛起》中的那一只猩猩!!!起源传说最早发明这个问题的人是法国数学家『爱德华·卢卡斯』。在世界中心贝拿勒斯(在印度 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 本文介绍了如何通过路由汇总和无类域间路由(CIDR)技术来优化路由表,减少路由条目数量,提高网络效率。具体案例展示了路由汇总的实现方法及其对网络性能的影响。 ... [详细]
  • 双指针法在链表问题中应用广泛,能够高效解决多种经典问题,如合并两个有序链表、合并多个有序链表、查找倒数第k个节点等。本文将详细介绍这些应用场景及其解决方案。 ... [详细]
  • 本文介绍了如何使用Visual Studio Code、Sublime Text等编辑器批量删除MATLAB代码中的注释和空行,同时提供了一些高级技巧以确保代码的整洁。 ... [详细]
  • 本文介绍了几种常用的图像相似度对比方法,包括直方图方法、图像模板匹配、PSNR峰值信噪比、SSIM结构相似性和感知哈希算法。每种方法都有其优缺点,适用于不同的应用场景。 ... [详细]
  • LintCode 1218. 计算补数的 JavaScript 算法
    本题要求给定一个正整数,计算其补数。补数是指将该数字的二进制表示逐位取反,然后转换回十进制得到的新数。 ... [详细]
  • 根据经济日报的报道,截至3月15日,包括抖音、今日头条、微信、淘宝、百度、大众点评、微博和小红书在内的多个主流App已经上线了算法关闭功能,用户可以在后台一键关闭“个性化推荐”。 ... [详细]
  • MATLAB实现Sobel边缘检测算法
    图像边缘是指图像中灰度值发生显著变化的区域。Sobel算子是一种常用的边缘检测方法,通过计算图像灰度值的梯度来检测边缘。本文介绍了Sobel算子的基本原理,并提供了基于MATLAB的实现代码。 ... [详细]
  • 本文详细介绍了如何使用OpenSSL自建CA证书的步骤,包括准备工作、生成CA证书、生成服务器待签证书以及证书签名等过程。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 本文详细介绍了在 Ubuntu 系统上搭建 Hadoop 集群时遇到的 SSH 密钥认证问题及其解决方案。通过本文,读者可以了解如何在多台虚拟机之间实现无密码 SSH 登录,从而顺利启动 Hadoop 集群。 ... [详细]
author-avatar
淀死鈊
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有