1,O(n)的算法,只有当我们可以修改输入的数组时可用
package case30_GetLeastNum;
/**
* 题目:输入n个整数,找出其中最小的k个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4
* 方法:利用partition函数完成,采用这种思路是有限制的。我们需要修改输入的数组,因为函数Partition会调整数组中数字的顺序
*
*
* @author WangSai
*
*/
public class GetLeastNum1 {
/**
*
* @param arr[]
* 需要被寻找的数组
* @return 寻找出来满足条件的k个数字
*/
public static void main(String[] args) {
int[] arr = { 4, 5, 1, 4, 4, 7, 3, 8 };
int k = 4;
getNumbers(arr, k);
}
// 通过partition函数,获取arrOut数组
private static void getNumbers(int[] arr, int k) {
// 异常值判断
if (arr == null || arr.length < k || arr.length <= 0 || k <= 0)
throw new IllegalArgumentException("输入的数组非法...");
// 采用递归的方式完成
int low = 0;
int high = arr.length - 1;
int index = partition(arr, low, high);
while (index != k - 1) {
if (index < k - 1) {
low = index + 1;
index = partition(arr, low, high);
} else {
high = index - 1;
index = partition(arr, low, high);
}
}
// 输出满足条件的数
for (int i = 0; i < k; i++)
System.out.print(arr[i] + " ");
}
// 快排中用到的partition函数
private static int partition(int[] arr, int low, int high) {
int pivotKey = arr[low];
while (low < high) {
while (low < high && arr[high] >= pivotKey)
high--;
arr[low] = arr[high];
while (low < high && arr[low] <= pivotKey)
low++;
arr[high] = arr[low];
}
arr[low] = pivotKey;
return low;
}
}
2,O(nlogk)的算法,特别适合处理海量数据
package case30_GetLeastNum;
/**
* 通过使用大顶堆完成。时间复杂度O(nlogk)
*
* @author WangSai
*
*/
public class ByHeap1 {
// 1,创建容器,并填充arr的前K个元素
// 2,对这[0...K-1]序列创建大顶堆
// 3,原序列从第K个开始,与[0...K-1]序列作比较,若大于堆顶元素则进行替换
// 4,替换完成后,对序列重新调整变成大顶堆
// 3,4步骤循环进行
public static void main(String[] args) {
int[] arr = { 1,2,3,4,5,6,7,8,4,433,32,0 };
int k = 4;
getLeatK(arr, k);
int[] arr1={1};
k =1;
getLeatK(arr1, k);
}
// 获取最小的K个元素的方法
private static void getLeatK(int[] arr, int k) {
// 异常情况检测
if (arr == null || arr.length <= 0 || arr.length < k || k <= 0)
throw new IllegalArgumentException("输入的参数非法,请重新检查...");
// 创建容器,并填充arr的前K个元素
int[] heap = new int[k];
for (int i = 0; i < k; i++) {
heap[i] = arr[i];
}
buildMaxTopHeap(heap);
// arr中的元素从第K个开始依次与大顶堆heap作比较,如果大于对顶则替换,并对新的堆做处理。
for (int i = k; i < arr.length; i++) {
if (arr[i] < heap[0]) {
heap[0] = arr[i];
adjustDownToUp(heap, 0);
}
}
for (int i = 0; i < heap.length; i++) {
System.out.print(heap[i] + " ");
}
System.out.println();
}
// 将含有K个元素的无序序列构建大顶堆
private static void buildMaxTopHeap(int[] heap) {
for (int i = heap.length / 2 - 1; i >= 0; i--) {
// 自底向上调整堆
adjustDownToUp(heap, i);
}
}
// 自底向上调整堆为大顶堆
private static void adjustDownToUp(int[] heap, int i) {
// 判断该节点与其子节点的大小
int temp = heap[i];
for (int j = 2 * i + 1; j < heap.length - 1; j = 2 *j + 1) { //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整
if (j <= heap.length - 1 && heap[j] < heap[j + 1]) //取节点较大的子节点的下标
j++; //如果节点的右孩子>左孩子,则取右孩子节点的下标
if (temp >= heap[j]) //根节点 >=左右子女中关键字较大者,调整结束
break;
//根节点 <左右子女中关键字较大者
else {
heap[i] = heap[j]; //将左右子结点中较大值array[i]调整到双亲节点上
i = j; //【关键】修改k值,以便继续向下调整
}
}
heap[i] = temp; //被调整的结点的值放入最终位置
}
}
3,O(n*k)的算法,用数组ArrayList保存K个数字,然后依次遍历数组arr中剩余的n-K个数字,依次比较并替换ArrayList中的最大值
package case30_GetLeastNum;
import java.util.ArrayList;
public class GetLeastNumByList {
public static void main(String[] args) {
//测试
int[] arr = { 4, 5, 1, 4, 4, 7, 3, 8 };
int k = 4;
ArrayList<Integer> alist = getNum(arr, k);
for (Integer num : alist)
System.out.print(num + " ");
}
//获取满足条件的最小的k个数字
private static ArrayList<Integer> getNum(int[] arr, int k) {
// 判断异常情况
if (arr == null || arr.length <= 0 || arr.length < k || k <= 0)
throw new IllegalArgumentException("非法的输入参数...");
// 新建容器,当容器中的数小于k的时候,直接添加。
ArrayList<Integer> alist = new ArrayList<>();
for (int i = 0; i < k; i++)
alist.add(arr[i]);
// 当容器满了之后,继续从剩下的arr[]数组的取出数。若取出来的数小于alist中最大的数,则直接替换掉。
for (int j = k; j < arr.length; j++) {
// 获取alist中最大的数值
int indexOfMaxValue = getMaxIndex(alist);
int max = alist.get(indexOfMaxValue);
// 若arr中当前的值小于alist中的最大值,则替换掉alist中的最大值
if (arr[j] < max) {
alist.set(indexOfMaxValue, arr[j]);
}
}
return alist;
}
// 获取arraylist中的最大数值的角坐标
private static int getMaxIndex(ArrayList<Integer> alist) {
int max = alist.get(0);
int i = 0;
for (int j = 1; j < alist.size(); j++) {
if (alist.get(j) > max) {
max = alist.get(j);
i = j;
}
}
return i;
}
}