堆排序:堆排序就是按照 大顶堆,小顶堆 的方式来进行排序,循环判断二叉树,每次循环判断得到一个值在二叉树顶端,然后依次与二叉树的最后一个值进行替换,每次替换二叉树的长度减一。
依次进行循环判断得到值然后顶端和末尾替换,从而实现了有序的排序。
思路:
1、将无序序列构成一个堆,根据需求创建成 大顶堆 或者 小顶堆
2、实现二叉树的堆顶元素和末尾元素的交换,将元素‘’沉‘到数组末端
3、重新调整结构,使其满足堆定义,然后继续交换堆顶元素和末尾元素,反复执行调整+交换,直到整个序列有序
测试代码:
package BinaryTree;
import java.util.Arrays;
public class HeadSortDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] arr = {3,7,1,9,2};
System.out.println("堆排序前的数组 = " + Arrays.toString(arr));
headsort(arr); //调用堆排序方法
System.out.println("堆排序后的数组 = " + Arrays.toString(arr));
}
public static void headsort(int [] arr) {
int temp = 0;
//2、实现二叉树的堆顶元素和末尾元素的交换,将元素‘’沉‘到数组末端
for(int i = arr.length / 2 - 1; i >= 0; i--) {
adjusthead(arr, i, arr.length);
}
//3、重新调整结构,使其满足堆定义,然后继续交换堆顶元素和末尾元素,反复执行调整+交换,直到整个序列有序
for(int j = arr.length - 1; j > 0; j--) {
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjusthead(arr,0,j);
}
}
//1、将无序序列构成一个堆,根据需求创建成 大顶堆 或者 小顶堆
public static void adjusthead(int [] arr,int i,int length) {
int temp = arr[i];
//说明:k = i * 2 + 1 表示的是结点的非叶子节点
for(int k = i * 2 + 1; k < length; k = k * 2 + 1) {//只要k小于数组的长度,就可以继续判断
//k = k * 2 +1表示继续判断子树
//1、k + 1 < arr.length,表示i结点是否具有右子树
//2、arr[k] > arr[k + 1]表示i节点的左子数的值是否大于右子树,大于则移动,用右子树的值与节点的值进行比较
if(k + 1 < length && arr[k] < arr[k + 1]) {
k++; //移动
}
//表示若i节点的值小于其子树的值,则进行替换
if(arr[k] > temp) {
arr[i] = arr[k]; //移动
i = k; //保存i节点的子结点的索引(方便后续进行交换),然后继续进行循环判断
} else {
break;
}
arr[i] = temp; //循环判断结束,进行赋值操作
}
}
}
详细思路测试代码:
package BinaryTree;
import java.util.Arrays;
/*
* 理解思路最为重要,大的思路知道如何实现,小的思路也要清楚!
* 1、将一个无序列表,根据我们的升序或降序的需求建成 大顶堆 或 小顶堆
* 2、实现 堆头和堆尾进行替换
* 3、定义合适的条件,使数组列表完成堆头和堆尾替换,形成一个有序列表。
*/
public class HeadSort_Review {
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] arr = {2,6,3,8,5};
System.out.println("没进行堆排序之前的数组为 " + Arrays.toString(arr));
adjusthead(arr, 1, arr.length);//2,8,3,6,5
System.out.println(Arrays.toString(arr));
headsort(arr);
System.out.println("实现了每个节点进行堆排序之后的数组为 " + Arrays.toString(arr));
//
}
//2、实现真正的 大堆头和堆尾进行替换
public static void headsort(int [] arr) {
int temp = 0;
//2.1:实现正确的定义,使每个节点都能够进行判断,如此才能实现堆排序
for(int i = arr.length / 2 - 1; i >= 0; i--) {
adjusthead(arr,i,arr.length);
}
//3、定义合适的条件,使数组列表完成堆头和堆尾替换,形成一个有序列表。
//3.1:定义一个temp保存变量,实现堆头和堆尾交换
//3.2:更改条件,使堆头和堆尾继续循环替换,知道形成一个有序列表停止
for(int j = arr.length - 1; j > 0;j--) {
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjusthead(arr,0,j);
}
}
//1、将一个无序列表,根据我们的升序或降序的需求建成 大顶堆 或 小顶堆
//1.1:创建一个方法,传入数组、传入结点、传入数组长度
public static void adjusthead(int [] arr,int i,int length) {
//1.2:定义一个局部变量,保存传入的结点的值
int temp = arr[i];
//1.3:根据传入的无序序列数组,根据需求 建立大顶堆或小顶堆
//1.31:定义传入的结点的子结点,循环判断
for(int k = i * 2 + 1; k < length; k = k * 2 + 1) {
//1.4:判断该节点是否存在右子结点 并且 左子结点是否大于右子结点
//1.41:若左子结点小于右子结点,则移动下标 使右子结点与父结点进行比较
if(k + 1 < length && arr[k] < arr[k+1]) {
k++;
}
//1.5:若结点不存在右子结点或者左子结点大于右子结点,则使左子结点和父结点进行比较,否则用移动后的 右子结点和父结点进行比较
if(arr[k] > temp) {
arr[i] = arr[k];
i = k;
}
arr[i] = temp;
}
}
}
来源:oschina
链接:https://my.oschina.net/u/4432600/blog/4288195