问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

不用排序怎样快速找到中位数,最好是一遍下来得到结果,求算法或者思路 谢谢!

发布网友 发布时间:2022-04-30 16:30

我来回答

5个回答

热心网友 时间:2023-10-09 00:12

这个比较不好讲清楚,先假设 A 和 B 都是升序的。

这个问题的关键在于给定 k,怎样找到 A 和 B 合并后的第 k 大元素。我们可以这样做:

1. 把 A 平均分为前后两个部分,前部分有 x 个元素,后部分有 n1-x 个元素(由于 A 是有序的,所以后一部分的所有元素大于前一部分)。A[x] = A的后一部分的第一个元素。
2. 同理把 B 也平均分成前后两个部分,前部分有 y 个元素,后部分有 n2-y 个元素。B[y] = B的后一部分的第一个元素。
3. 由于两个数组都是被平均分割的,所以可以近似地认为 x = n1/2, y = n2/2。

这里不妨设 A[x] <= B[y](如果 A[x] > B[y] 处理过程和下面类似):

=============================== 情况1 ============================

由于在 A 中,A[x] 前面有 x 个元素,在 B 中,B[y] 前面有 y 个元素,并且又有 A[x] <= B[y],那么,合并以后,A[x]前面原来那些元素必然也在B[y]前面,也就是说,B[y]前面至少会有 x + y 个元素,我们再规定如果 A, B 中有相同元素,则合并后 A 中的元素排在 B 前面,那么归并以后 A[x] 也会排在 B[y] 前面,于是乎合并之后 B[y] 至少有 x+y+1 个元素。

如果 k <= x+y+1,也就是说,合并后第 k 大的元素必然落在 B[y] 前面。所以,原来在 B 数组中,第二部分(B[y]以及 B[y] 之后)那些元素都不可能包含我们要找到内容(第 k 大元素),所以我们可以把他们排除掉。这样就排除了 B 中一半的内容。

=============================== 情况2 ============================

在 A 中,A[x] 及其后面有 n1-x 个元素,除去 A[x] 之后有 n1-x-1 个元素,B[y] 及其后面有 n2-y 个元素。那么,由于 A[x] <= B[y],所以合并起来之后,B[y] 后面那些元素必然也在 A[x] 后面,则合并后 A[x] 后面至少有 (n1-x-1) + (n2-y) = (n1+n2)-(x+y+1) 个元素。

如果 k > x+y+1,也就说,合并后第 k 大的元素必然落在 A[x] 后面。所以,原来在 A 数组中,第一部分(A[x]之前)以及 A[x] 都不可能包含我们要找的元素,所以我们可以把他们排除掉。这样就排除了 A 中一半的内容。

============================ 下面是总结 ===========================

综上所诉,对于 k <= x+y+1 还是 k > x+y+1 我们都提出了解决的方案,并且每种方案都能把 A 或者 B 的规模减小一半。减小了一半之后,我们将其作为一个新的问题继续使用上面的算法处理,直到 A 或者 B 减小到足够小:

1. A没有了,这样只需要找出 B 中第 k 大的元素,也就是 B[k].
2. B没有了,同上结果就是 A[k].

达到以上两个条件的任意一个分别只需要 O(logn1) 和 O(logn2) 的时间,所以最坏情况下这个算法只需要 O(logn1 + logn2) 就能得出结果。

============================ 下面是程序 ===========================

以下是基于这个算法的程序,具体实现是在 element_at 这个函数中,通过调用 element_at(0, n1-1, 0, n2-1, k) 可返回 A, B 数组合并后第 k 大的元素。

#include <stdio.h>

int n1, n2;
int A[1000];
int B[1000];

int element_at(int l1, int r1, int l2, int r2, int k) {
int x = (l1 + r1) / 2, y = (l2 + r2) / 2;

if (l1 > r1) return B[l2+k-1];
if (l2 > r2) return A[l1+k-1];

if (A[x] <= B[y]) {
if (k <= (x - l1) + (y - l2) + 1) {
return element_at(l1, r1, l2, y-1, k);
} else {
return element_at(x+1, r1, l2, r2, k-(x-l1)-1);
}
} else {
if (k <= (x - l1) + (y - l2) + 1) {
return element_at(l1, x-1, l2, r2, k);
} else {
return element_at(l1, r1, y+1, r2, k-(y-l2)-1);
}
}

return 0;
}

int main() {
int i;
printf("请输入A的大小:");
scanf("%d", &n1);
printf("请输入%d个数,以空格隔开:",n1);
for (i = 0; i < n1; i++) scanf("%d", &A[i]);

printf("请输入B的大小:");
scanf("%d", &n2);
printf("请输入%d个数,以空格隔开:",n2);
for (i = 0; i < n2; i++) scanf("%d", &B[i]);

if ((n1 + n2) & 1) {
printf("中位数是:%d\n", element_at(0, n1-1, 0, n2-1, (n1+n2)/2+1));
} else {
printf("中位数是:%lf\n", (element_at(0, n1-1, 0, n2-1, (n1+n2)/2) + element_at(0, n1-1, 0, n2-1, (n1+n2)/2+1)) / 2.0);
}

return 0;
}追问谢谢你的回答,你说的现在是 A 和 B 数组是有序的情况! 现在主要他们都是无序的呀!我可以吧这些数分成A B 两个数组但是不能保证A B 的顺序和 大小是多少!这个怎么考虑!谢谢!

热心网友 时间:2023-10-09 00:12

比如 1-9 这9个数字的中位数是 5

这些数的和是 45
temp = 5*0.618=3.09
比如现在的顺序是 189234675
然后 temp每次修正 temp= temp * n/2(n-m) n是 数组 个数 m 是 小于 temp 的 个数
一遍下来 big = {8,9,4,6,7,5}
samll = {1,2,3}
现在 修正 temp = 3.09*9/6 =4.635

一遍下来 big = {8,9,6,7,5}
samll = {1,2,3,4}
temp = 4.635*9/8=5.214375

一遍下来 big = {8,9,6,7}
samll = {1,2,3,4,5}
temp = 5.214375 * 9/8

边界是 count(big) - count(samll) < =1
这样 最后 可以得到 中位数 但是 效率
不高

用的 原来就是 中位数 的 大于他的 和小于他的 个数 一样

对应算法是 search_zhong.php

<?php
$arr = array();//定义数组
for($i=0;$i<=1000;$i++){//假设有 1001个数字 现在随机生成
$arr[] = rand(0,10000);
}
$arr_s = $arr;
$time = time();//排序前开始计时
sort($arr);//对数组 排序

$zhongwei = $arr[501];//中位数
echo '中位数是:'.$zhongwei.'找到中位数用了'.time()-$time.'秒
';
$time2 = time();

echo '中位数是:(用马乙说的方法)'.mayiFunc($arr_s,0,0).'找到中位数用了'.time()-$time2.'秒
';

function mayiFunc($arr,$temp,$m){
$n = count($arr);
if($temp == 0){
$sum = array_sum($arr);
$agv = $sum/count($arr);
$temp = $agv*0.618;
}else{
$temp = $temp * $n/(2*($n-$m));
}

$big = array();
$small = array();
foreach($arr as $a){
if($a>$temp){
$big++;
}
else{
$small++;
}
}
if($big>$small){
if($big-$small<=1){
echo $temp;
exit;
return $temp;
}
else{
mayiFunc($arr,$temp,$small);//迭代调用
}
}else{
if($small-$big<=1){
echo $temp;
exit;
return $temp;
}
else{
mayiFunc($arr,$temp,$big);//迭代调用
}
}

}

这样感觉效率还是不高!

热心网友 时间:2023-10-09 00:12

所有数相加,在除以2,奇数的话就把相加结果加一在除以2。
望采纳

热心网友 时间:2023-10-09 00:13

如果是几十万个正整数的话,可以构造一个数组,数组的长度是数据中的最大值。假设为array[max],数组置零。
遍历所有数字n,令array[n]+=1。
遍历array,sun+=array[i],若sun>=length/2,终止遍历,i即为中位数。
可能直接无法构造巨大的数组,那就用树来构造一个

热心网友 时间:2023-10-09 00:14

如果你了解快速排序的话,用一下方法可以实现。
首先把问题转化为求一列数中第i小的数的问题,求中位数就是求一列数的第(length/2+1)小的数的问题。
然后调用快速排序中的partition函数q=partition(A,0,lenght);
1--q>length/2,那就调用A[q=partition(A,0,q-1)];
2--q=lengh/2,return A[q];//找到
3--q<length/2,调用A[q=partition(A,q+1,length,length/2-q+1)];
以上默认此序列长度为奇数,如果为偶数就是第调用上述方法两次找到中间的两个数求平均。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
怎样移动手机应用的位置 不戴安全套但没有射精会怀孕吗 青岛哪所学校空乘专业就业率高 属牛的是什么星座1985年 m.xzw.com m.xingzuo360.cn 敏卡·凯利基本信息 想问一下eve用什么船刷古斯塔斯怪比较好?如果能有配置图就更好了... EVE加达里恐惧古斯塔斯小型控制塔一个月要多少燃料块 eve古斯塔斯据点需要打建筑么? 对煮饭手艺好的 应该用什么词语修饰 去哪里搜上海中小学教师招聘信息呢,怎么找都找不到呀,大家来帮帮忙吧... 难言之已(我怎么了,跟男朋友接吻不到10秒钟就想离开) 数学中位数怎么找 怎样找出一组数据中的中位数?数学题 形容难言的成语 怎样找出一组数据中的中位数? 喜爱佳入口难言,欢声笑语把心折,你若皎月在心间,这首诗的意思? 为什么帮别人承担责任叫做背黑锅?有什么典故吗? 数据太多怎么才能简便的求中位数,就像是40个数,还有中位数,众数,平均数分别表示什么 《难言之隐》txt全集下载 怎么找中位数?谢谢! 难言之隐 找中位数的最快方法 难言之处是什么意思 难言之欢by卡戎星小说在哪里看啊 手机在京东以旧换新的方式回收后得到的E卡有什么作用 网上的游戏主播是用什么软件把视频剪切成竖屏的样子? 想入坑当一枚主播啊,想问一下那些主播用的什么视频编辑软件,怎样在视频后面做一个短视频列出自己的微博 怎么鉴定买的瓷器餐具是否有毒? 陶瓷碗上透明秞起泡是什么问题! 买的据说是骨瓷杯,用不锈钢汤匙在里面搅水后有些划痕,像铅笔划的一 难言之隐啊 如何快速求出一大组数据中的中位数? “新型啃老”正在蔓延,年轻人浑然不知,老人早已有苦难言,对此你怎么看? 怎样找中位数 有什么难言之隐 找一组数据的中位数,众数有什么窍门。 有难言之隐吗 什么是中位数?怎样找中位数?中位数数表示什么? 控制必须有明确的控制( ),形成相应的控制机制。 控制的必要性表现为哪些方面? 梦见抓红鲤鱼。小鲤鱼。鲫鱼。后来被红鲤鱼咬了,有水,后来鱼都跑了剩一个黑鲤鱼和一个红鲤鱼,水也不多 实现有效控制的基本要求是什么? 控制原理都有哪些内容? 梦见好多鲤鱼 控制的要素是什么? 控制标准都有哪些分类要求? 名词解释:控制职能? 回到明朝当王爷韩幼娘为杨凌挡刀是哪一集? 回到明朝当王爷之杨凌传韩幼娘结局死了吗 我用微信绑定银行卡,然后显示 你的证件号与银行预留信息不符 这是什么情况?