算法分析系列文章中的代码可被任何人无偿使用于任何场景且无需注明来源也不必在使用前征得本文作者同意。
算法分析系列文章旨在传播准确、完整、简洁、易懂、规范的代码实现,并传授基本的编程思想和良好的编码习惯与技巧。
若文章中的代码存在问题或逻辑错误,请通过邮件等形式(见文章结尾)告知于本文作者以便及时修正错误或改进代码。
算法系列文章不可避免地会参考和学习众多网友的成果,在行文风格、内容及求解思路上也会进行借鉴,如有侵权嫌疑,请联系本文作者。
PS:若为转载该文章,请务必注明来源,本站点欢迎大家转载。
问题描述
给定含有n个元素的多重集合S
,每个元素在S
中出现的次数称为该元素的重数。多重集S
中重数最大的元素称为众数(mode)。
例如,S={1,2,2,2,3,5}
,则,多重集S
的众数是2
,其重数为3
。
注:众数可能存在多个。
本案例要求采用分治法求解给定集合中的众数及其重数,存在多个众数时选择第一个即可。
分治法,即,把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。(引用自「维基百科」)
求解思路
分治法求解的基本思路就是将集合分成几个小部分,依次查找每个部分中的众数,再从每个部分中取出重数最大的数,该数即为所求解的众数。
在分治求解过程中,当枢轴元素(pivot)所在位置的左右两侧剩余的数据量均小于pivot
的重数时,则求解结束且所求的众数即为pivot
的值。
实现代码
1 |
|
以上代码应该能够很容易看懂。这里主要强调以下几点:
- 对外传播的代码应该尽量降低阅读者的理解难度以及时间成本
- 变量名、函数名一定要能够清晰、准确地传达出其所代表的东西以及其职能,不要简单使用
i
、j
等无意义的名称,更不要使用语义不清甚至是错误的单词 - 函数实现代码一般按照调用先后顺序和重要性进行排列以便于阅读并突出关键实现等
- 注释主要用于阐明流程、算法机制和原理、特殊代码技巧以及在调整或改进时需特别注意的事项等内容,切记不要对代码本身进行说明,说明也不要又臭又长。PS:本文为了能让刚入门的开发者看懂并阐述算法机制和过程,所以,注释写得比较详细,在实际开发中可以默认视为阅读者具备相关的算法基础,从而无需再对算法进行注释说明
- 一般通过
sizeof(data) / sizeof(data[0])
方式动态计算数组长度
实现改进
上面的代码在调用sort_and_find_pivot()
后存在一次遍历以获得pivot
的重数(pivot_cnt
),但实际上在sort_and_find_pivot()
排序过程中已经存在等值比较,在这个时候是可以顺便得到pivot
的重数的,只是限于C语言的函数只能返回一个值的约束而无法同时返回其重数。不过,C语言提供结构体类型,故而,可以通过在sort_and_find_pivot()
后返回结构体的方式以避免不必要的遍历。
以下为改进后的代码:
1 |
|
这里主要强调以下几点:
- 在离调用最近的位置处声明变量,避免变量声明位置与第一次使用位置相隔太远
- 结构体数据的初始化采用(ANSI) C99方式以便于阅读,如,
struct point p = { .y = yvalue, .x = xvalue };