文章目录

  • 基本堆排序
  • 1.有20个数组,每个数组有500个元素,且是有序的,如何在20*500个数中找出排名前500的数
    • 设有两个递增的序列a,b 长度都为n,求前k个最小的a[i]+b[j]
    • 若要在N个海量数据(超过10亿,不能一次性放入内存)中找出最大的k个元素,(内存中可以容纳k个元素),最好采取什么数据结构和策略?
  • 归并排序
    • 设有一个整数序列,求数组中一共多少个逆序对
  • 快速排序

基本堆排序

堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图
调整为大根堆:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。

a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
https://www.cnblogs.com/chengxiao/p/6129630.html

void shif(int a[],int low,int high)
{int i = low,j = 2*i;//j为左孩子int temp = a[i];while(j <= high){if(j < high && a[j] < a[j+1])//如果右孩子更大j++;if(temp < a[j]){//如果根节点小于最大孩子a[i] =a[j];//将a[j]调整到双亲结点位置上i = j;j = 2*i;//继续向下调整}else break;//如果根节点大于等于最大的左右孩子}a[i] = temp;
}
void HeapSort(int a[],int n)
{int i;for(i = n/2;i >= 1;i--){shif(a,i,n);//初始化循环建立堆}for(i = n;i >= 2; i--)//进行n-1趟堆排序,每一趟堆中元素个数减一{swap(a[i],a[1]);//将最后一个元素与a[1]交换shif(a,1,i-1);//对a[1..i-1]进行筛选,得到i-1个结点的堆}
}int main() {int a[6]={0,11,74,3,15,6};
HeapSort(a,5);
for(int i = 1;i <= 5;i++)
cout<<a[i]<<" ";}
  • 每一趟通过堆调整产生有序区,它是全局有序区
  • 每次调整时间为o(log2n)
  • 产生初始堆的时间为o(n),比较次数约4n
  • 最好最坏和平均时间复杂度为o(nlog2n)
  • 是不稳定的排序算法

应用:STL中的priority_queue优先队列
一旦元素在优先队列容器中,删除操作将删除最高优先级元素

1.有20个数组,每个数组有500个元素,且是有序的,如何在20*500个数中找出排名前500的数

涉及知识点:

priority_queue中元素的比较 模板申明带3个参数:priority_queue<Type, Container, Functional>Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector。
比较方式默认用operator<,所以如果把后面2个参数缺省的话,优先队列就是大顶堆(降序),队头元素最大
仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。

template <class T>
struct greater : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x > y; }
};

题目思路:假设元素类型为int,有序数组的个数为max,利用堆结构,堆中结点类型为node,用vectormyv存储结果。
下面是假如有三个有序数组,找出前三个最小的元素的代码:

#include<stdio.h>
#include<vector>
#include<queue>
#define max 3
struct node{//小根堆的结点类型int pn;//段号int sn;//该段号中元素的序号int data;//元素值
};
struct cmp{bool operator() (const node& s1, const node& s2)const{return s1.data > s2.data;//创建小根堆}
};void Top(int *a[max],vector<int>&myv)
{priority_queue<node, vector<node>, cmp>qu;//优先队列,注意其中的三个参数 这样每次出队时都是元素值最小的结点struct  node e;for(int i = 0;i < max; i++){e.pn = i;e.sn = 0;e.data = a[e.pn][e.sn];//将所有段的首元素入队qu.push(e);}for(int i = 0;i < max; i++){e = qu.top(); qu.pop();
myv.push_back(e.data);//元素值插入到vector中
e.sn++;//该段的下一个元素入队
e.data = a[e.pn][e.sn];qu.push(e);}
}void dis(vector<int>p)
{vector<int>::iterator it;for(it = p.begin() ; it != p.end(); it++){cout<< *it<<" ";}
}int main() {int a1[3] = {2,6,9};
int a2[3] = {-1,-1,5};
int a3[3] = {-3,2,4};
vector<int> my;
int *a[max];
a[0] = a1;
a[1] = a2;
a[2] = a3;
Top(a,my);
dis(my);}

设有两个递增的序列a,b 长度都为n,求前k个最小的a[i]+b[j]

与上一题类似,利用小根堆,先将a[0]+b[0]插入到小根堆qu中,当k>0时循环,出队元素e,插入到result中,k–,vector<node>result存放结果


void Top(int a[],int b[],int n,int k,vector<node>&p)//求前k个最小和
{priority_queue<node>qu;//优先队列,注意跟上一题比较,这里只需要一个参数 这样每次出队时都是元素值最小的结点struct  node e,temp;   e.i = 0;e.j = 0;e.data = a[e.i]+b[e.j];qu.push(e);while(k){e = qu.top(); qu.pop();
p.push_back(e);
k--;
if(e.j+1 < n){temp.i = e.i;
temp.j = e.j + 1;
temp.data = a[temp.i++]+b[temp.j];
qu.push(temp);
}
if(e.j == 0 && e.i+1< n)//将a[e1.i+1]+b[e1.0]入队
{temp.i = e.i+1;
temp.j = e.j;
temp.data = a[temp.i]+ b[temp.j];
qu.push(temp);
}}
}void dis(vector<node>p)
{for(int i = 0;i < p.size(); i++){cout<< p[i].data<<" ";}
}int main() {int a[3] = {2,4,5};
int b[3] = {1,2,6};
vector<node>vec;
Top(a,b,3,6,vec);dis(vec);}

注:在b没有扫描完时将a[e1.i]+b[e1.j+1]入队,当e.j = 0时还要将a[ei.i+1]+b[e1.0]入队

经过自己的试验,去掉e.j == 0 && 这句话,输出结果也是一样的

若要在N个海量数据(超过10亿,不能一次性放入内存)中找出最大的k个元素,(内存中可以容纳k个元素),最好采取什么数据结构和策略?

首先读入k个元素,假设第一次读取的k个元素就是前k个最大元素,把k个元素建成小根堆,然后从第k+1个元素开始,读取的每个元素d都与堆顶元素进行比较,如果元素d大于堆顶元素,则把堆顶的元素替换成d,再将其调整为小根堆,当所有数据都读入并比较完之后,这个小根堆里面的所有元素就是最大的k个元素。

归并排序

分为自底向上的非递归过程和自顶向下的递归过程,每一趟产生的是局部有序区, 其最好 最坏 平均时间复杂度均为o(nlog2n)
是不稳定的排序算法。
空间复杂度为o(n)
(快速排序的空间复杂度是o(log2n)

设有一个整数序列,求数组中一共多少个逆序对

可以采用归并排序,在合并的过程中计算逆序数,这是一种高效的算法,时间复杂度远小于暴力解法。
设low<=i<=mid,mid+1<=j<=high,当a[i]<=a[j]时不产生逆序对,当a[i]>a[j]时逆序数有mid-i+1个(注意两半分别已经排好序了)

int sum;
void merge(int a[], int low, int mid, int high)
{int i = low;int j = mid + 1;int *tmp = (int *) malloc((high - low +1)* sizeof(int));//分配足够空间int k = 0;while(j <= high && i <= mid){if(a[i] > a[j])
{sum += mid - i + 1;tmp[k++] = a[j++];
}
else tmp[k++] = a[i++];}while(j <= high)tmp[k++] = a[j++];while(i <= mid)tmp[k++] = a[i++];for(int k1 = 0;k1 < k;k1++)a[low+k1] = tmp[k1];//把tmp[0..k-1]复制到a[low..high]中free(tmp);//释放空间
}void merge_sort(int a[],int low,int high)
{if(low < high){//注意一开始的条件判断int mid = (low + high)/2;merge_sort(a,low,mid);//先不断递归 得到最底层的数字 再合并merge_sort(a, mid+1, high);merge(a,low,mid,high);}
}int main() {int a[5] = {3,1,4,5,2};
merge_sort(a, 0, 4);
cout<<sum;}

快速排序

快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进行交换,交换的距离就大得多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的,都是O(N2),它的平均时间复杂度为O (NlogN)。其实快速排序是基于一种叫做“二分”的思想。

#include <stdio.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left,int right)
{int i,j,t,temp;
if(left>right)
return;
temp=a[left]; //temp中存的就是基准数
i=left;
j=right;
while(i!=j)
{//顺序很重要,要先从右往左找
while(a[j]>=temp && i<j)
j--;
//再从左往右找
while(a[i]<=temp && i<j)
i++;
//交换两个数在数组中的位置
if(i<j)//当哨兵i和哨兵j没有相遇时
{t=a[i];
a[i]=a[j];
a[j]=t;
}
}
//最终将基准数归位
a[left]=a[i];
a[i]=temp;
quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程
quicksort(i+1,right);//继续处理右边的,这里是一个递归的过程
}
int main()
{int i,j,t;
//读入数据
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n); //快速排序调用
//输出排序后的结果
for(i=1;i<=n;i++)
printf("%d ",a[i]);
getchar();getchar();
return 0;
}

【算法学习笔记】堆排序和归并排序、其他几种排序的代码实现、比较和应用(习题)相关推荐

  1. 大顶堆删除最大值_算法学习笔记(47): 二叉堆

    堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小).当根节点保存堆中最大值时,称为大根堆:反之,则称为小根堆. 二叉堆(Binary Heap)是最简单.常用的堆,是一 ...

  2. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  3. 数据结构与算法学习笔记之 从0编号的数组

    数据结构与算法学习笔记之 从0编号的数组 前言 数组看似简单,但掌握精髓的却没有多少:他既是编程语言中的数据类型,又是最基础的数据结构: 一个小问题: 为什么数据要从0开始编号,而不是 从1开始呢? ...

  4. 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序

    拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...

  5. 算法学习笔记:对指定金额计算最少钞票数

    算法学习笔记:对指定金额计算最少钞票数 一.引出问题 财务人员给员工发工资时经常遇到这样一个问题,即根据每个人的工资额(以元作为单位)计算出各种面值的钞票的张数,且要求总张数最少.例如,某职工工资为3 ...

  6. matlab中x从0到5不含0,关于MATLAB的数学建模算法学习笔记

    关于MATLAB的数学建模算法学习笔记 目录 线性规划中应用: (3) 非线性规划: (3) 指派问题;投资问题:(0-1问题) (3) 1)应用fmincon命令语句 (3) 2)应用指令函数:bi ...

  7. 机器学习篇01:在线学习的支持向量机算法学习笔记

    在线学习的支持向量机算法学习笔记 oisvm算法实现说明 oisvm算法实现说明 % 本程序是用于实现基于在线学习的调制信号识别的程序 % % % 第一步:调制信号的生成 % 首先是7个信号:2ASK ...

  8. 数据结构与算法学习笔记之 提高读取性能的链表(上)

    数据结构与算法学习笔记之 提高读取性能的链表(上) 前言 链表(Linked list)比数组稍微复杂一点,在我们生活中用到最常见的应该是缓存,它是一种提高数据读取性能的技术,常见的如cpu缓存,浏览 ...

  9. l2-004 这是二叉搜索树吗?_算法学习笔记(45): 二叉搜索树

    二叉搜索树(Binary Search Tree, BST)是一种常用的数据结构,在理想情况下,它可以以 的复杂度完成一系列修改和查询,包括: 插入一个数 删除一个数 查询某数的排名(排名定义为比该数 ...

  10. 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列

    (为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...

最新文章

  1. php软件安装及调试_PHP调试利器XDebug的安装与使用
  2. Oracle中删除用户和表空间的常见问题(比如:ORA-01940无法删除当前已连接用户的解决方案)
  3. 《梦断代码》读书笔记
  4. [渝粤教育] 西南科技大学 英语口语 在线考试复习资料
  5. NS-仿真实验--FTP
  6. 今天我离开了工作四年的大宇
  7. 基于visual Studio2013解决C语言竞赛题之0701排队输出
  8. 如何防止社工钓鱼——软件伪造
  9. 施耐德电气技术文档集
  10. 华为手机鸿蒙系统官方下载入口,华为鸿蒙系统升级入口
  11. 自然语言处理之词移距离Word Mover's Distance
  12. SCC算法求强连通分量简单讲解证明及实现
  13. vue中添加mp3音频文件
  14. 实现antd中Form、Form.Item组件
  15. 三维空间几何变换矩阵
  16. python结合mitmproxy抓包实践
  17. java将字符串内容转换为字节数组
  18. 技本功丨互联网+工业视觉异常检测分析
  19. qtp15/uft15 UFT最新版本UFT12.5
  20. 神策数据唐予轩:一文看懂效果广告渠道追踪能力搭建与分析

热门文章

  1. php excel导入mysql_使用PHPExcel导入Excel到MySql
  2. java如何解决高并发症,一整套Java线上故障排查技巧,爱了!
  3. marbin mysql_跨浏览器图像灰度(grayscale)解决方案
  4. python 如何匹配列表中某个单词_Python如何匹配文本文件中多行中的特定单词/数字,并将它们存储在单独的列表中...
  5. 宁波大学2013 计算机应用基础 高级c语言程序 练习册答案,2020年宁波大学计算机应用技术考研真题试卷及试题答案,计算机系统基础考研试题下载...
  6. 2010 模板下载 罗斯文_俄罗斯签证办理攻略
  7. php和dart的区别,Dart相等和关系运算符
  8. 我的世界java版移除猪灵了吗_我的世界:激怒僵尸猪灵有奖励,用菌光体堆肥,修复126个漏洞!...
  9. 解决 pandas 读取数据时内存过大的问题
  10. 六、继续学习Java的位运算符,发现真的简单