排序 第K大等问题总结
在公司面试时,当场写排序比较多,虽然都是老掉牙的问题,还是要好好准备下
快速排序,以第一个元素为关键词比较,每次比较结束,关键词都会去到最终位置上
//7 3 2 9 8 3 4 6
//7 3 2 9 8 5 4 6
//7 5 2 9 8 3 4 6 #include<stdio.h>
int s[];
void mysort(int left,int right){
if(left>=right)return; int mid,key=s[left];
int ll=left,rr=right;
while(ll<rr){
while(s[rr]>=key&&ll<rr)rr--;
s[ll]=s[rr];
while(s[ll]<=key&&ll<rr)ll++;
s[rr]=s[ll];
}s[ll]=key;
mysort(left,ll-);
mysort(ll+,right);
} int main(){
int n;
while(scanf("%d",&n)!=EOF){
int i,k;
for(i=;i<=n;i++){
scanf("%d",&s[i]);
} mysort(,n);
for(i=;i<=n;i++){
printf("%d\n",s[i]);
}
} return ;
}
改了下,更通俗了些
#include<stdio.h>
#include<time.h>
#include<iostream>
using namespace std; int shu[]={,,,,,,,,,}; void quickSort(int left,int right){
if(left>=right) return ;
int ll=left,rr=right;
int temp=shu[left];
while(ll<rr){
while(temp<=shu[rr]&&rr>left)rr--;
while(temp>=shu[ll]&&ll<right)ll++;
if(ll>=rr)break;
swap(shu[ll],shu[rr]);
}
swap(shu[left],shu[rr]);
quickSort(left,rr);
quickSort(rr+,right);
} int main(){
int i,n=;
for(i=;i<=n;i++){
shu[i]=rand()%;
printf("%d ",shu[i]);
}
quickSort(,n); for(i=;i<=n;i++){
printf("%d ",shu[i]);
}
getchar();
}
第k大的元素,其实就是在快速排序的基础上对递归做了个限制,就是对一边进行递归, 比如Kth的位置在key的左边,我们就递归(left,ll-1);反之(ll+1,right)
//7 3 2 9 8 3 4 6 1
//7 3 2 9 8 3 4 6 2
//7 3 2 9 8 3 4 6 3
//7 3 2 9 8 3 4 6 4
//7 3 2 9 8 3 4 6 7 #include<stdio.h>
int s[]; int findKth=,kth;
void kth_element(int left,int right){
if(left>=right)return;
if(findKth==){
return ;
} int mid,key=s[left];
int ll=left,rr=right;
while(ll<rr){
while(s[rr]>=key&&ll<rr)rr--;
s[ll]=s[rr];
while(s[ll]<=key&&ll<rr)ll++;
s[rr]=s[ll];
}s[ll]=key;
if(kth<ll)
kth_element(left,ll-);
else if(kth>ll)
kth_element(ll+,right);
else{
findKth=;
return ;
}
} int main(){
int n;
while(scanf("%d",&n)!=EOF){
int i,k;
for(i=;i<=n;i++){
scanf("%d",&s[i]);
}
scanf("%d",&kth);
findKth=;
kth_element(,n);
printf("%d\n",s[kth]); //mysort(1,n);
for(i=;i<=n;i++){
printf("%d ",s[i]);
}printf("\n");
} return ;
}
改的适合自己的模板
#include<stdio.h>
#include<time.h>
#include<iostream>
using namespace std; int shu[]={,,,,,,,,,};
int key,ret;
int ok; void Kth(int left,int right){
if(ok==)return;
if(left>=right) return ;
int ll=left,rr=right;
int temp=shu[left];
while(ll<rr){
while(temp<=shu[rr]&&rr>left)rr--;
while(temp>=shu[ll]&&ll<right)ll++;
if(ll>=rr)break;
swap(shu[ll],shu[rr]);
}
swap(shu[left],shu[rr]);
if(rr==key){
ok=;
ret=shu[rr];
return ;
} if(key<rr)
Kth(left,rr);
else
Kth(rr+,right);
} int main(){
int i,n=;
srand(time(NULL));
for(i=;i<=n;i++){
shu[i]=rand()%;
printf("%d ",shu[i]);
}printf("\n"); key=;
ok=;
Kth(,n); for(i=;i<=n;i++){
printf("%d ",shu[i]);
}printf("\n");
printf("kth = %d\n",ret);
getchar();
}
根据堆的定义,堆是一个完全二叉树,手写了个大顶堆,其实堆就两个操作,入堆(需要向上调整),出堆(需要向下调整),堆排序就是依次把堆顶元素出堆
向上调整不需要选择,因为祖先只有一个;向下调整需要选择是从左子树还是右子树,因为儿子可能有两个
#include<iostream>
#include<cstdio>
#include<time.h>
using namespace std;
double test[],s[]; int head_size;
void head_push(int k,double temp){//入堆其实是一个向上调整的过程
int n=k;
s[k]=temp;
while(n!=){
if(s[n/]<s[n]){
swap(s[n/],s[n]);
}
n=n/;
}
return ;
} void head_pop(){//堆顶元素出堆其实是向下调整的过程
int n=;
s[]=s[head_size+];
while(n*<=head_size){
if(n*+<=head_size){//右儿子存在
if(s[n]>=s[*n+]&&s[n]>=s[*n])break;//父节点比两个儿子都大退出
if(s[*n+]>s[*n]){ //右儿子比左儿子大
swap(s[n],s[*n+]);
n=n*+;
}else{ //左儿子比右儿子大
swap(s[n],s[*n]);
n=n*;
}
}
else{//只存在左儿子
if(s[n]>=s[*n])break;//父节点比左儿子大退出
swap(s[n],s[*n]);
n=n*;
}
}
return;
} void headSort(double *input,int left,int right){
int i;
head_size=;
for(i=left;i<=right;i++){
head_size++;
head_push(head_size,input[i]);
} for(i=left;i<=right;i++){
input[i]=s[];
head_size--;
head_pop();
} int half=(left+right)>>;
double temp;
for(i=left;i<=half;i++){//因为是大顶堆,所以要调整
temp=input[i];input[i]=input[right-i+];input[right-i+]=temp;
} } int main(){
freopen(" data.txt","r",stdin);
time(NULL);
int i; for(i=;i<=;i++){
scanf("%lf",&test[i]);
}
headSort(test,,); printf("第1个:%lf\n",test[]);
printf("第10个:%lf\n",test[]);
printf("第100个:%lf\n",test[]);
printf("第1000个:%lf\n",test[]);
printf("第10000个:%lf\n",test[]); return ;
}
//发现原来的堆排序写的有点罗嗦,改了一下
#include<iostream>
#include<stdio.h>
using namespace std; int head_size;
int s[]={,,,,,,,,,};
int temp[]; //大顶堆
void shiftUp(int a[],int i){
while(i>&&a[i]>a[i/]){
swap(a[i],a[i/]);
i>>=;
}
} void shiftDown(int a[],int i,int n){
while((i*)<=n){
i<<=;
if((i+)<=n && a[i+]>a[i])i++;
if(a[i]>a[i/])swap(a[i],a[i/]);
else break;
}
} void headSort(int a[],int n){
head_size=n;
int i;
for(i=;i<=n;i++){
shiftUp(s,i);
}
for(i=;i<=n;i++){
temp[i]=s[];
s[]=s[n+-i];
head_size--;
shiftDown(s,,head_size);
} for(i=;i<=n;i++){
s[i]=temp[i];
}
} int main(){
int n=,i;
headSort(s,n);
for(i=;i<=n;i++){
printf("%d\n",s[i]);
} return ;
}
//这个数据量可以控制
#include<stdio.h>
#include<time.h>
#include<iostream>
using namespace std; int shu[]={,,,,,,,,,};
int newShu[]; void shiftUp(int a[],int n){
int i=n,next;
while(i>){
next=i>>;
if(a[i]>a[next])
swap(a[i],a[next]);
i=next;
}
} void shiftDown(int a[],int n){
int i=;
while((i<<)<=n){
i=i<<;
if((i+)<=n&&a[i+]>a[i])i++;
if(a[i]>a[i/])swap(a[i],a[i/]);
}
} void headSort(int n){
int i;
for(i=;i<=n;i++){
shiftUp(shu,i);
}
for(i=;i<=n;i++){
newShu[i]=shu[];
shu[]=shu[n-i+];
shiftDown(shu,n-i);
}
} int main(){
int i,n=;
srand(time(NULL));
for(i=;i<=n;i++){
shu[i]=rand()%;
printf("%d ",shu[i]);
}printf("\n"); headSort(n); for(i=;i<=n;i++){
printf("%d ",newShu[i]);
}printf("\n"); getchar();
}
希尔排序是插入排序的一种变形,是步长不短缩小的插入排序
#include<iostream>
#include<cstdio>
#include<time.h>
using namespace std;
double test[] ; void shellsort(double *s,int left,int right) {//希尔排序是插入排序的一种变形,步长逐渐缩小的插入排序
for (int step = right/ ;step>; step/=) {
for (int i = step; i <=right; i++) {
double temp = s[i];
int j = i;
while (j >= step && temp < s[j - step]) {
s[j] = s[j - step];
j -= step;
}
s[j] = temp;
}
}
}
int main(){
freopen(" data.txt","r",stdin);
time(NULL);
int i; for(i=;i<=;i++){
scanf("%lf",&test[i]);
}
shellsort(test,,); printf("第1个:%lf\n",test[]);
printf("第10个:%lf\n",test[]);
printf("第100个:%lf\n",test[]);
printf("第1000个:%lf\n",test[]);
printf("第10000个:%lf\n",test[]); return ;
}
/*插入排序与希尔排序的实例比较*/
希尔排序有时被叫做缩减增量排序(diminishing increment sort),使用一个序列h1,h2,h3……这样一个增量序列。只要h1=1时,任何增量序列都是可以的。但有些可能更好。对于希尔排序为什么会比直接插入排序快的原因,我们可以来看一个比较极端的例子: 假如对于一个数组{,,,,,,,}以从小到大的顺序来排。直接插入排序显然是很悲剧的了。 它的每次排序结果是这样的: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 然后我们来看看Shell排序会怎样处理,一开始步长为4 数组分为8, , , 5和4, , , 首先是8和4进行比较,交换位置。 变成了4, , , 5和8, , , 同理7和3,6和2,5和1也是样的,所以当步长为4时的结果是: , , , , , , , 可以看到,大的数都在后边了。 接下来的步长为2 这一步过程就多了很多: 一开始是4和2进行比较,交换,得到: , , , , , , , 3和1比较,交换,得到: , , , , , , , 接下来是4和8,3和7,这两个比较没有元素交换。接下来8和6,7和5就需要交换了。所以步长为2时的结果就是: , , , , , , , 可以明显地感觉到,数组变得“基本有序”了。 接下来的步长1,变成了直接插入排序。手动模拟一下就可以发现,元素的交换次数只有四次!这是相当可观的。也由此我们可以得到一个基本的事实:对于基本有序的数组,使用直接插入排序的效率是很高的!
转自:http://www.cnblogs.com/yjiyjige/archive/2013/08/13/3256138.html
归并排序,思考将两个有序数列变成一个有序数列的过程,归并就是由小到大重复这个过程,最终使数组有序
#include<iostream>
#include<cstdio>
#include<time.h>
using namespace std;
double test[],temp[]; void unsort(double *s,int left,int right){ int mid=(left+right)>>;
if(mid-left>=)unsort(s,left,mid);
if(right-mid>=)unsort(s,mid+,right); int i,p1=left,p2=mid+;
for(i=left;i<=right;i++){//两个有序数组变成一个有序数组
if(p1>mid){
temp[i]=s[p2];
p2++;
continue;
}
if(p2>right){
temp[i]=s[p1];
p1++;
continue;
}
if(s[p1]<=s[p2]){
temp[i]=s[p1];
p1++;
}else{
temp[i]=s[p2];
p2++;
}
}
for(i=left;i<=right;i++){ //转移
s[i]=temp[i];
}
} int main(){
freopen(" data.txt","r",stdin);
time(NULL);
int i; for(i=;i<=;i++){
scanf("%lf",&test[i]);
}
unsort(test,,); printf("第1个:%lf\n",test[]);
printf("第10个:%lf\n",test[]);
printf("第100个:%lf\n",test[]);
printf("第1000个:%lf\n",test[]);
printf("第10000个:%lf\n",test[]); return ;
}
排序 第K大等问题总结的更多相关文章
- 【转载】两个排序数组的中位数 / 第K大元素(Median of Two Sorted Arrays)
转自 http://blog.csdn.net/zxzxy1988/article/details/8587244 给定两个已经排序好的数组(可能为空),找到两者所有元素中第k大的元素.另外一种更加具 ...
- 编写函数求整形数组a中存储的m个不重复的整数的第k大的整数(其中m>=1,1<=k<=m)很简单的一个思路是酱紫的:管他辣么多干啥,上来一把排序然后直接得答案
/** * @author:(LiberHome) * @date:Created in 2019/2/28 20:38 * @description: * @version:$ *//*编写函数求整 ...
- 给定两个数组,这两个数组是排序好的,让你求这两个数组合到一起之后第K大的数。
题目:给定两个数组,这两个数组是排序好的,让你求这两个数组合到一起之后第K大的数. 解题思路: 首先取得数组a的中位数a[aMid],然后在b中二分查找a[aMid],得到b[bMid],b[bSt] ...
- 【基础算法】排序-复杂排序之二(找出第K大的数)
切割的思想是高速排序最精髓的地方.每一次切割出来的元素K一个排在第K位,所以利用这样的思想我们至少知道3点 1. 被切割出来的元素K最后一定排在第K位. 2. 在K左边的元素一定比K小或者相等. 3. ...
- [LeetCode] Kth Largest Element in an Array 数组中第k大的数字
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...
- 区间第K大(一)
Problem: 给定无序序列S:[b, e),求S中第K大的元素. Solution 1.裸排序 2.现将区间均分成两段,S1, S2,对S1,S2分别排序,然后
- 寻找数组中的第K大的元素,多种解法以及分析
遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程.问题:寻找数组中的第K大的元素. 最简单的想法是直接进行排序,算法复杂度是O(N*logN).这么做很明显比较低效率,因 ...
- [51nod1685]第k大区间
Description 定义一个长度为奇数的区间的值为其所包含的的元素的中位数. 现给出$n$个数,求将所有长度为奇数的区间的值排序后,第$k$大的值为多少. Input 第一行两个数$n$和$k$. ...
- 数据结构2 静态区间第K大/第K小
给定数组$A[1...N]$, 区间$[L,R]$中第$K$大/小的数的指将$A[L...R]$中的数从大到小/从小到大排序后的第$K$个. "静态"指的是不带修改. 这个问题有多 ...
随机推荐
- 2.spring cloud eureka client配置
红色加粗内容表示修改部分 1.把server项目打成jar包并启动 在项目根目录cmd执行 mvn clean package -Dmaven.test.skip=true mavne仓库地址建议 ...
- 031——VUE中表单控件处理之使用vue控制input和textarea表单项
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- C#学习历程(四)[实际问题]
>>无法直接启动带有”类库输出类型”的项目 在编辑界面的右侧会出现[解决方案资源管理器],里面显示我们的程序项目和所有代码文件. 右键点击项目,在右键菜单中选择[属性] 一般导致该问题都是 ...
- yum 认知及使用
https://www.cnblogs.com/zhichaoma/p/7533247.html
- New Concept English there (3)
25words/ minutes Some time ago,an interesting discovery was made by archaeologists on the Aegean isl ...
- vscode 实用插件
1.Auto Rename Tag,非常实用!要修改标签名称的时候自动修改结束标签,节省一半时间,提升效率,非常棒! 2.vscode-icon,这款必须要推荐,明显提升效率的小插件,在项目文件多类型 ...
- c# 系统校时工具类
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HuaT ...
- 一张图说明HTTPS 握手过程
- CuratorFramework入门指南
CuratorFramework入门指南 原文地址:https://github.com/Netflix/curator/wiki/Getting-Started CuratorFramework作为 ...
- hessian 协议 版本 兼容
环境 : 服务端: hessian 4.0.38 , spring 4.3.6 ; spring文档指出spring4.0以上的版本只能使用hessian 4.0以上的版本 客户端: hessian ...