針對動態(tài)數(shù)據(jù)越走,求排序后處于中間的數(shù)據(jù)
思路:維護(hù)兩個堆,一個大頂堆催享,一個小頂堆杭隙。大頂堆中存儲前半部分?jǐn)?shù)據(jù),小頂堆中存儲后半部分?jǐn)?shù)據(jù)因妙,且小頂堆中的數(shù)據(jù)都大于大頂堆中的數(shù)據(jù)痰憎。如果有 n 個數(shù)據(jù),n 是偶數(shù)攀涵,從小到大排序铣耘,那前 n/2? 個數(shù)據(jù)存儲在大頂堆中,后 n/2個數(shù)據(jù)存儲在小頂堆中以故。這樣蜗细,大頂堆中的堆頂元素就是我們要找的中位數(shù)。如果 n 是奇數(shù)怒详,情況是類似的炉媒,大頂堆就存儲 n/2?+1 個數(shù)據(jù),小頂堆中就存儲 n/2? 個數(shù)據(jù)昆烁。
//數(shù)據(jù)數(shù)組
private int[] data = new int[10];
//數(shù)據(jù)大小
private int size;
//大頂堆數(shù)據(jù)數(shù)組
private int[] bigHeap = new int[5];
//大頂堆數(shù)據(jù)大小
private int bigHeapSize;
//小頂堆數(shù)據(jù)數(shù)組
private int[] smallHeap = new int[5];
//小頂堆數(shù)據(jù)大小
private int smallHeapSize;
//添加數(shù)據(jù),暫不考慮擴(kuò)容吊骤,固定數(shù)組大小。添加數(shù)據(jù)不會超標(biāo).
public void add(int value) {
data[size++] = value;
//偶數(shù)情況下静尼,大頂堆n/2白粉,小頂堆n/2传泊,奇數(shù)情況下,大頂堆n/2+1,小頂堆n/2.且大頂堆的數(shù)據(jù)比小頂堆多
if (size % 2 == 0) {
//大頂堆堆頂元素大于該元素鸭巴,將大頂堆元素刪除眷细。放入小頂堆。該元素加入大頂堆奕扣。
int temp = value;
if (bigHeap[0] > value) {
temp = bigHeap[0];
bigHeap[0] = value;
bigHeapAdjust(bigHeap, 0, bigHeapSize);
}
smallHeap[smallHeapSize++] = temp;
smallHeapAdjust(smallHeap,0, smallHeapSize);
} else {
//和小頂堆堆頂元素大小判斷
int temp = value;
if (smallHeapSize != 0 && smallHeap[0] < value) {
temp = smallHeap[0];
smallHeap[0] = value;
smallHeapAdjust(smallHeap, 0, smallHeapSize);
}
bigHeap[bigHeapSize++] = temp;
bigHeapAdjust(bigHeap,0, bigHeapSize);
}
}
public int medianNum() {
return bigHeap[0];
}
public static void smallHeapAdjust(int[] data, int index, int length) {
int temp = data[0];
for (int i = index * 2 + 1; i < length; i = i * 2 + 1) {
if (i + 1 < length && data[i] > data[i + 1]) {
//左孩子節(jié)點(diǎn)大于右孩子節(jié)點(diǎn)薪鹦,指向右孩子
i++;
}
//如果該結(jié)點(diǎn)比最小的孩子節(jié)點(diǎn)小,退出
if (temp < data[i]) {
break;
}
//將最小的孩子結(jié)點(diǎn)的值賦值給該結(jié)點(diǎn)
data[index] = data[i];
index = i;
}
data[index] = temp;
}
public static void bigHeapAdjust(int[] data, int index, int length) {
//從該結(jié)點(diǎn)的左子結(jié)點(diǎn)開始惯豆,也就是2i+1處開始
int temp = data[index];
for (int i = index * 2 + 1; i < length; i = i * 2 + 1) {
if (i + 1 < length && data[i] < data[i + 1]) {
//左孩子節(jié)點(diǎn)小于右孩子節(jié)點(diǎn)池磁,指向右孩子
i++;
}
//如果該結(jié)點(diǎn)比最大的孩子節(jié)點(diǎn)大,退出
if (temp >= data[i]) {
break;
}
//將最大的孩子結(jié)點(diǎn)的值賦值給該結(jié)點(diǎn)
data[index] = data[i];
index = i;
}
data[index] = temp;
}