问题描述
给定一个数组,找出其中出现次数最多的那个元素(即众数)。
例如:
1 2 2 2 3 5
众数是: 2
算法思路:先排序 后用分治法计算求解
分治法求解代码如下:
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
/*----------快速排序*/
int Partition(int *a , int l , int r)
{
int i = l , j = r+1;
int x = a[l];
while(true){
while(a[++i] < x && i < r);
while(a[--j] > x);
if(i >= j) break;
swap(a[i] , a[j]);
}
a[l] = a[j];
a[j] = x;
return j;
}
/*------------随机选择中位数排序*/
int RandomizedPartitiom(int *a , int l , int r)
{
srand(time(NULL));
int i = rand()%(r-l)+l;
swap(a[i] , a[l]);
return Partition(a , l , r);
}
/*----------------按中位数划分成两段*/
void split(int *a , int m , int l , int r , int *left , int *right)
{
int med = a[m];
*left = *right = m;
/*--------------------将 == 中位数的元素剔除:及 right-left+1 == 众数的个数*/
while(a[--(*left)] == med);
while(a[++(*right)] == med);
(*left)++;
(*right)--;
}
/*---------------分治法求解*/
void mode(int *a , int l , int r , int *largest , int *count)
{
int m = RandomizedPartitiom(a , l , r);//----查找中位数
int left , right;
split(a , m , l , r , &left , &right);//---按中位数分成2段
if(*largest < right-left+1){//-----保留众数个数最大值,及众数下标
*largest = right-left+1;
*count = m;
}
if(left-l > *largest) mode(a , l , left-1 , largest , count);//左边个数大于众数个数
if(r-right > *largest) mode(a , right+1 , r , largest , count);//右边个数大于众数个数
}
/*----------main()*/
int main()
{
int n;
cout<<"请输入集合S的元素个数n:"<<endl;
cin>>n;
int a[n];
int largest = 0 , count = 0;
cout<<"请输入元素:"<<endl;
for(int i = 0 ; i < n ; i++)
cin>>a[i];
mode(&a[0] , 0 , n-1 , &largest , &count);
cout<<"众数是:"<<a[count]<<"\t重数是:"<<largest<<endl;
return 0;
}
/*
请输入集合S的元素个数n:
6
请输入元素:
1 2 2 2 3 5
众数是:2 重数是:3
Process returned 0 (0x0) execution time : 7.504 s
Press any key to continue.
*/