描述:
给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。
多重集S中最大重数的元素称为众数。
例如S={1,2,2,2,3,5}。多重集S的众数是2,重数是3。
- 分治策略
- 首先假设中间的元素是众数
- 然后由中间向两边遍历,直到左右都出现值不等于众数的数,记录下众数和重数
- 这样就将一个数组分为三部分,对左右部分执行上述步骤
- 注意:使用分治策略解决众数问题需要原集合有序,在原集合无序的情况下需要对其排序
使用数组与C++语言进行示范
#include <iostream>
using namespace std;
int mode = 0; //使用全局变量,记录众数的值,初始为0
int sum = 0; //使用全局变量,记录众数的重数,初始为0
void Merge(int *arr, int left, int middle, int right) { //归并算法
int *temp = new int [right-left+1];
int i = left;
int j = middle + 1;
int k = 0;
while (i <= middle && j <= right) {
if (arr[i] <= arr[j])
temp[k++] = arr[i++];
else
temp[k++] = arr[j++];
}
while (i <= middle)
temp[k++] = arr[i++];
while (j <= right)
temp[k++] = arr[j++];
for (i = 0; i < k; i++)
arr[i + left] = temp[i];
delete[] temp;
}
void MergeSort(int *arr, int left, int right) { //归并算法
if (left < right) {
int middle = (left + right) / 2;
MergeSort(arr, left, middle);
MergeSort(arr, middle + 1, right);
Merge(arr, left, middle, right);
}
}
void GetMode(int *arr,int left, int middle, int right) { //分治策略获得众数
int tempMode = arr[middle]; //假设中间的数是众数
int tempSum = 1;
int i = middle - 1;
while (arr[i] == tempMode) { //向左边扩展
tempSum++;
i--;
}
int j = middle + 1;
while (arr[j] == tempMode) { //向右边扩展
tempSum++;
j++;
}
if (tempSum > sum) { //如果假设的众数比原来的众数的 重数 大,则替换
sum = tempSum;
mode = tempMode;
}
/*
这里分别对划分出来的左右两部分进行递归
在进行递归前先判断左右两部分的长度是否大于 重数
大于重数证明划分出来的部分可能存在另外的众数
*/
if(i-left+1 >sum)
GetMode(arr, left, (left + i) / 2, i);
if(right - j +1> sum)
GetMode(arr, j, (j + right) / 2, right);
}
int main()
{
int n;
cout << "Input n: ";
cin >> n;
int* arr = new int[n];
for (int i = 0; i < n; i++)
cin >> arr[i];
MergeSort(arr, 0, n - 1); //对数组进行众数的寻找前,先对数组进行排序
GetMode(arr, 0, n / 2, n - 1);
cout << "mode=" << mode << ", sum=" << sum;
return 0;
}