求无序数组中元素出现次数超过数组长度一半的数字.

这篇博客探讨了如何在无序数组中找到一个出现次数超过数组长度一半的数字。通过分析排序后的数组中位数特性,提出了一种递归查找的方法,先随机选择一个数字,然后根据其位置缩小搜索范围。但需要注意,应先判断数组是否存在这样的元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求无序数组中元素出现次数超过数组长度一半的数字.

首先给出几个"元素出现次数超过数组长度一半"测试数组:

a1[7]={1 ,2, 3 , 5 , 3 , 3  , 3};

a2[5]={5, 3, 5, 5, 1};

a3[9]={8 ,5 ,6 ,5 ,4 ,2 ,5 ,5 ,1};

不难发现:

   数组中如果一个数字出现次数超过数字长度的一半.如果把这个数组排序,那么排序后的数组中间的数字一定是出现次数超过数字长度的一半.

   如数组a1长度为7,按从小到大排序后为a1[7]={1,2,3,3,3,3,5},此时数组中间的数字a[7/2]=2就是要找的数字.

   如数组a2长度为5,按从小到大排序后为a2[5]={1,3,5,5,5},此时数组中间的数字a[5/2]=5就是要找的数字.

   如数组a3长度为9,按从小到大排序后为a3[9]={1,2,4,5,5,5,5,6,8},此时数组中间的数字a[9/2]=5就是要找的数字.

   

    所以有了以上的发现,我们就可以先随机选择数组中的一个数字,然后进行排序,使比它小的数字位于它左边,使比它大的数字位于它右边.

如果选中的这个数下标恰好是n/2,那么这个数字就是数组的中位数,

如果它的下标大于n/2,那么它的下标大于n/2,那么中位数在它的左边,我们便可以继续在左边递归查找,   

 如果它的下标小于n/2,那么它的下标小于n/2,那么中位数在它的右边,我们便可以继续在右边递归查找.

 

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>  
int  qort(int arr[], int left, int right)
{
	int tmp = arr[left];
	while (left < right)
	{

		while (left < right && arr[right] >= tmp)
		{
			right--;
		}
		if (arr[right] < tmp)
		{
			arr[left] = arr[right];
			arr[right] = tmp;
		}
		while (left<right && arr[left] <= tmp)
		{
			left++;
		}
		if (arr[left]>tmp)
		{
			arr[right] = arr[left];
			arr[left] = tmp;
		}
	}
	return right;

}
int SelectHalfNum(int *arr,int len)
{
	int left = 0;
	int right = len-1;
	int tem = qort(arr, left, right);
	int middle = len / 2;
	while (tem != middle)
	{
		if (tem > middle)
		{
			right = tem - 1;
			tem = qort(arr, left, right);
		}
		else
		{
			left = tem + 1;
			tem = qort(arr, left, right);
		}
	}
	printf("%d\n", arr[middle]);
}
int main()
{
	int arr[] = {1,2,2,5,2};
	int len = sizeof(arr) / sizeof(arr[0]);
	SelectHalfNum(arr, len);
	system("pause");
	return 0;
}

以上代码有个Bug,那就是应该对数组进行判断,判断数组是否存在出现次数大于数组长度的元素.

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h> 

int  qort(int arr[], int left, int right)
{
	int tmp = arr[left];
	while (left < right)
	{
		while (left < right && arr[right] >= tmp)
		{
			right--;
		}
		if (arr[right] < tmp)
		{
			arr[left] = arr[right];
			arr[right] = tmp;
		}
		else
		{
			break;
		}
		while (left<right && arr[left] <= tmp)
		{
			left++;
		}
		if (arr[left]>tmp)
		{
			arr[right] = arr[left];
			arr[left] = tmp;
		}
		else
		{
			break;
		}
	}
	return right;
}

int CheckNum(int *arr, int len, int val)
{
	int cout = 0;
	int i = 0;
	for (i = 0; i < len; i++)
	{
		if (arr[i] == val)
		{
			cout++;
		}
	}
	if (cout > len/2)
	{
		return 1;
	}
	return 0;
}

int  SelectHalfNum(int *arr, int len)
{
	int left = 0;
	int right = len - 1;
	int tem = qort(arr, left, right);
	int middle = len / 2;
	while (tem != middle)
	{
		if (tem > middle)
		{
			right = tem - 1;
			tem = qort(arr, left, right);
		}
		else
		{
			left = tem + 1;
			tem = qort(arr, left, right);
		}
	}
	int ret = arr[middle]; 
	if (CheckNum(arr,len,ret)!=0)
	{
		return ret;
	}
	return 0;
}

int main()
{
	int arr[] = { 1, 2, 5, 2 };
	int len = sizeof(arr) / sizeof(arr[0]);
	printf("%d", SelectHalfNum(arr, len));
	system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值