求最小的k个数问题

查找最小的k个元素
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。

我的思路:利用二叉堆,构建一个容量为k的定长最小二叉堆,遍历数组,逐个将元素add进堆,完毕返回堆中所有元素即为最小的k个元素



package org.jf.alg;

/**
* 定长小根堆
* 数组存储,数组第一个元素留空
*
* 第k个元素的左儿子为 a[2k],右儿子为a[2k+1]
*
* 第k个元素的父节点为a[k/2]
*
* k从1记起
*
* @author chenjf
*
*
*/
public class LittleHeadFixedBinHeap<T extends Comparable>
{

private Object array[];
private int current_size = 0;

/**
*
* @param size 堆大小
*/
public LittleHeadFixedBinHeap(int size)
{
array = new Object[size+1];

}

public LittleHeadFixedBinHeap(int size,T []data_array)
{
array = new Object[size+1];
for(int i=0;i<data_array.length;i++)
{
this.add(data_array[i]);
}
}

/**
* 往堆中添加一个元素
*
*分两种情况:
*1.当前堆未满,直接添加到末尾,回溯保持堆性质
*2.当前堆已满,则找出最后一层中最大元素并与当前元素比较,若当前元素小,则替换,否则什么也不做
*
* @param data
*/
public void add(T data)
{
int comp_begin = current_size/2+1;//求最大值的起始位置
int indx = 1;//记录当前新插入的元素索引
if(current_size<array.length-1)//堆未满 直接将新元素插入末尾
{
array[++current_size]=data;
indx = current_size;
}
else//堆已满 查找最后一层中的最大值
{

int max_indx = comp_begin;
T max = (T) array[max_indx];
int i=comp_begin;
while(i<array.length)
{
if(max.compareTo((T)array[i])<0)
{
max_indx = i;
max = (T) array[max_indx];
}

i++;
}

if(max.compareTo(data)>0)
{
indx = max_indx;
array[indx] = data;//当前的最大值被删除了

}
else
{
indx = 1;//不替换
}

}

//向上检测
while(indx>1)
{
//当前元素与其父节点比较 若小,则交换 indx = indx/2
//否则 break
int pdx = indx/2;
if(((T)array[indx]).compareTo(((T)array[pdx]))<0)
{
Object tmp = array[indx];
array[indx] = array[pdx];
array[pdx]=tmp;
indx = pdx;
}else
{
break;
}
}
}


/**
* 删除堆顶元素
* 删除堆顶,用最后一个元素代替堆顶,向下检测保持堆性质
*
* @return
*/
public T remove()
{
T data = null;
if(current_size==0)
return null;


data = (T) array[1];
array[1] = array[current_size];
array[current_size] = null;
current_size -- ;

//根节点与左右子节点中最小元素交换

int indx = 1;

int min_indx =indx;
Object tmp = null;
while((min_indx=getMinIndx(indx))!=indx)
{
//indx 与 min_indx元素交换
tmp = array[indx];
array[indx]=array[min_indx];
array[min_indx]=tmp;
indx = min_indx;
}

return data;
}


private int getMinIndx(int indx)
{

T left = null;
T right = null;
if(indx*2>this.current_size)//没有子节点
return indx;
if(indx*2==this.current_size)
left = (T)array[indx*2];
else
{
left = (T)array[indx*2];
right =(T)array[indx*2+1];
}

if(right==null)
{

if(left.compareTo((T)array[indx])<0)
indx = indx*2;

}else
{
if(left.compareTo((T)array[indx])<0)
{
indx = indx*2;
if(right.compareTo((T)array[indx])<0)
indx = indx+1;
}
else if(right.compareTo((T)array[indx])<0)
{
indx = indx*2+1;
}
}

return indx;
}

public T peek()
{
if(this.current_size>0)
return (T) array[1];

return null;
}


public int capacity()
{
return array.length-1;
}

void printArray()
{
for(int i=1;i<=this.current_size;i++)
{
System.out.print(array[i].toString()+" ");
}
System.out.println("\n");
}


public Object [] getAll()
{
Object[] newArray = new Object[this.current_size];
System.arraycopy(array, 1, newArray, 0, current_size);
return newArray;
}


public static void main(String args[])
{
Integer array[] = new Integer[]{3,5,2,6,7,-1,8,0,9,-10};
LittleHeadFixedBinHeap heap = new LittleHeadFixedBinHeap(5,array);
heap.printArray();
}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值