zoukankan      html  css  js  c++  java
  • 【u119】中位数

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    给出一个长度为N的非负整数序列A[i],对于所有1 ≤ k ≤ (N + 1) / 2,输出A[1], A[2], …, A[2k - 1]的中位数。即前1,3,5,……个数的中位数。


    【输入格式】

    输入文件median.in的第1行为一个正整数N,表示了序列长度。 第2行包含N个非负整数A[i] (A[i] ≤ 10^9)。

    【输出格式】

    输出文件median.out包含(N + 1) / 2行,第i行为A[1], A[2], …, A[2i – 1]的中位数。

    【数据规模】

    对于20%的数据,N ≤ 100; 对于40%的数据,N ≤ 3000; 对于100%的数据,N ≤ 100000。

    Sample Input1

    7
    1 3 5 7 9 11 6
    
    
    
    
    
    
    
    
    

    Sample Output1

    1
    3
    5
    

    6

    【题解】

    维护一个大根堆和一个小根堆。

    一开始把第一二元素加入到大根堆的第一个位置。然后直接输出第一个元素。

    对于之后输入的元素。进行判断。如果大于大根堆的根,则放到小根堆。小于或等于则放到大根堆。

    然后放完之后。进行一次判断。看一下这两个堆它们的差的绝对值是否会大于2.如果大于2的话。就把数字

    多的那个堆中的根放到另外一个堆中。这样的判断也做完之后。就可以输出中位数了。比如当前i=3,则中

    位数的位置就在2,先判断一下2是否等于大根堆的大小,如果是就输出大根堆的根,否则输出小根堆的根。

    难点的话在堆的操作上。多熟悉就懂了。

    【代码】

    #include <cstdio>
    
    int dagendui[100001],xiaogendui[100001],n,pos; //拼音分别对应了大根堆和小根堆 
    
    void up_tiaozheng(int a[100001],int p,int what) //往上调整。 what对应了a堆是什么堆 
    { //0为大根堆 1为小根堆 
    	int x = a[p]; //获取需要调整的数字 
    	int i = p,j = p/2; //往上调整 所以是除2表示指向其父亲节点 
    	//printf("p=%d
    ",p);
    	while (j > 0) //如果没有越过树的范围 
    		{
    			if (what ==0) //大根堆 的调整方法 
    				{
    					if (x > a[j]) //如果这个值比父亲节点大。那么就不符合大根堆的定义了。 
    						{ //往上走 
    							a[i] = a[j];
    							i = j;
    							j = i/2;
    						}
    						else //否则就找到了一个合适的位置 直接结束即可。 
    							break;
    				}
    					else //小根堆 
    						{
    							if (x <a[j]) //如果父亲节点比儿子节点大。则不符合小根堆的定义。 
    								{ //同样进行调整 
    									a[i] = a[j];
    									i = j;
    									j = i/2;	
    								}
    								else //如果找到合适的位置就直接结束调整 
    									break;
    						}
    		}
    	a[i] = x;
    	pos = i; //要记录这个数字最后放到了哪里。 
    }
    
    void down_tiaozheng(int a[100001],int p,int what) //往下调整。 
    {
    	int x = a[p]; //获取需要调整的数字。 
    	int i = p,j = p*2;
    	while (j <=a[0] )
    		{
    			if (what ==0) //大根堆 
    				{
    					if (j < a[0] && a[j+1] > a[j]) //大根堆往下调整的话,儿子要找大的。 
    						j++;
    					if (x < a[j])
    						{
    							a[i] = a[j];
    							i = j;
    							j = i*2;	
    						}
    						else
    							break;
    				}
    					else //小根堆 
    						{
    							if (j < a[0] && a[j+1] < a[j]) //小根堆要调整则要找小的。 
    								j++;
    							if (x > a[j])
    								{
    									a[i] = a[j];
    									i = j;
    									j = i*2;
    								}
    									else
    										break;
    						}
    		}
    	a[i] = x;
    }
    
    void input_data()
    {
    	scanf("%d",&n);
    	scanf("%d",&dagendui[1]); //先把第一个元素放到大根堆的根节点。 
    	dagendui[0] = 1;
    	printf("%d
    ",dagendui[1]);
    	for (int i = 2;i <= n;i++)
    		{
    			int dd;
    			scanf("%d",&dd);//输入的数据和大根堆的根节点比较  
    			if (dd > dagendui[1]) //根据比较的结果放到大根堆或小根堆。 
    				{
    					xiaogendui[0]++;
    					xiaogendui[xiaogendui[0]]=dd;
    					up_tiaozheng(xiaogendui,xiaogendui[0],1); //放到末尾要先向上调整再向下调整 
    					down_tiaozheng(xiaogendui,pos,1);
    				}
    				else
    					{
    						dagendui[0]++;
    						dagendui[dagendui[0]] = dd;
    						up_tiaozheng(dagendui,dagendui[0],0);				
    						down_tiaozheng(dagendui,pos,0);		//同理 											
    					}
    			if (dagendui[0] > xiaogendui[0]) //如果它们的大小之差的绝对值大于2则需要调整 
    				{
    					if ((dagendui[0] - xiaogendui[0]) > 2) //大根堆数字比较多 
    						{ //就把大根堆的根节点放到小根堆中去 
    							xiaogendui[0]++;
    							xiaogendui[xiaogendui[0]] = dagendui[1];
    							up_tiaozheng(xiaogendui,xiaogendui[0],1);
    							down_tiaozheng(xiaogendui,pos,1);							
    							dagendui[1] = dagendui[dagendui[0]];
    							dagendui[0]--;
    							down_tiaozheng(dagendui,1,0);
    						}
    				}
    				else 
    					if (dagendui[0] < xiaogendui[0])
    						{
    							if ((xiaogendui[0]-dagendui[0]) > 2)
    								{ //如果小根堆中的数字更多。则把小根堆的根节点放到大根堆中去。 
    									dagendui[0]++;
    									dagendui[dagendui[0]] = xiaogendui[1];
    									up_tiaozheng(dagendui,dagendui[0],0);
    									down_tiaozheng(dagendui,pos,0);
    									xiaogendui[1] = xiaogendui[xiaogendui[0]];
    									xiaogendui[0]--;
    									down_tiaozheng(xiaogendui,1,1);																		
    								}
    						}
    			if ( (i%2)==1) //如果是奇数 则输出大根堆的根节点或小根堆的根节点。 
    				{
    					int tt = (i+1)/2;
    					if (tt ==dagendui[0]) //大根堆的大小和所需要输出的第tt个数字相同就可以直接输出根节点 
    						printf("%d
    ",dagendui[1]);
    							else //否则的话就是放在小根堆的根节点了。 
    								printf("%d
    ",xiaogendui[1]);
    				}
    		}
    		
    }
    
    int main()
    {
    	//freopen("F:\rush.txt","r",stdin);
    	input_data();
    	return 0;	
    }


  • 相关阅读:
    java--Compara比较字符串排序(引用类型都可以)
    java---递归遍历文件
    java 增强for循坏遍历set 集合嵌套
    java-手写实现map
    ajax请求拿到多条数据拼接显示在页面中
    ajax取到数据后如何拿到data.data中的属性值
    .NET CORE IIS 500.21
    ConfigurationErrorsException: Unrecognized configuration section system.data.
    关于ajax中return并不能作为方法的返回值
    .net core 的跨域
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632337.html
Copyright © 2011-2022 走看看