堆的概念:
如果将序列{k1 , k2 , … , kn}对应为一维数组,且序列中元素的下标与数组中下标一致,即数组中下标为 0 的位置不存放数据元素,此时该序列可看成是一颗完全二叉树,则堆的定义说明,在对应的完全二叉树中非终端结点的值均不大于(或不小于)其左右孩子结点的值。
堆排序:
其实感觉画图可以把问题说明,不过我就不画图了。简单的几句话觉得更能说明问题。
第一步,建立堆结构(完全二叉树可以存储到数组中);
第二步,不断的输出堆顶元素,输出后并调整堆的结构,使其重新成为一个堆。
public void heapAdjust(int[] array,int low,int high) {
int parentNode = array[low];
for (int j=2*low; j<=high; j=j*2){
//沿关键之较大的元素向下进行筛选
//j 指向关键之较大的元素
if (j<high && (array[j] < array[j+1])) //j < high防止没有右子树的情况
j++;
//若 parentNode 比其孩子都大,那么退出循环
if (parentNode >= array[j]) {
break;
} else { //否则沿着交换的路径继续向下比较
array[low] = array[j];
low = j;
}
}
array[low] = parentNode;
}
public void heapSort() {
int[] array = {0,28,26,17,36,20,42,11,53};
int n = array.length - 1;
//这里为小技巧,i=n/2为一个完全二叉树的最后一个叶子节点的父节点,然后沿逆时针方向倒叙
//遍历每一个父节点
for (int i=n/2; i>=1; i--) {//4 3 2 1
heapAdjust(array,i,n);
}
for (int i=n; i>1; i--) {
//不断输出堆顶元素并调整 array[1..i-1]为新堆
int temp = array[1];
//交换堆顶与堆底元素
array[1] = array[i];
array[i] = temp;
heapAdjust(array,1,i-1);
}
for(int i = 0;i<=n;i++)
System.out.println(array[i]);
}
</pre><pre name="code" class="java">
2,优先级队列,其实堆就是一种特殊的优先级队列。每次取数据的时间复杂度为1(把优先级最高的元素取出),插入元素的过程为把一个元素插入到有序的队列之中(按优先级排序)时间复杂度为log2N。
下面给出了一种插入算法和一种二分查找算法,只要把二分查找变为二分查找后插入就可以了。
</pre><pre name="code" class="java"><pre name="code" class="java">public static void main(String args[]) {
int[] array = {1,2,3,4,5,6,7};
System.out.println(erfinsert(array,1,0,6));
}
public void insert(int[] array, int insertData, int reallength) {
int i, j;
if (insertData < array[0]) {
for (i = reallength; i > 0; i--) {
array[i] = array[i - 1];
}
array[i] = insertData;
} else if (insertData > array[reallength - 1]) {
array[reallength] = insertData;
} else {
for (i = 0; i < reallength; i++) {
if (insertData > array[i] && insertData <= array[i + 1]) {
for (j = reallength; j > i; j--) {
array[j] = array[j - 1];
}
array[j] = insertData;
break;
}
}
}
}
public static int erfinsert(int[] arr, int data, int low,int high) {
int mid = 0;
while(low <= high) {
mid = (low + high)/2;
if(arr[mid] == data)
return mid;
else if(arr[mid] > data) {
high = mid -1;
continue;
} else if(arr[mid] < data) {
low = mid +1;
continue;
}
}
return -1;
}
下面补充一个折半插入排序吧:
public void binInsertSort(int[] array, int low, int high) {
for (int i = low + 1; i <= high; i++) {
int temp = array[i];
// 保存待插入元素
int hi = i - 1;
int lo = low;
// 设置初始区间
while (lo <= hi) {
// 折半确定插入位置
int mid = (lo + hi) / 2;
if (temp < array[mid])
hi = mid - 1;
else
lo = mid + 1;
}
for (int j = i - 1; j > hi; j--)
array[j + 1] = array[j]; // 移动元素
array[hi + 1] = temp;
// 插入元素
}// for
}