七大常用的排序算法——堆排序实现

我怕爱的太早我们不能终老 提交于 2020-10-04 14:27:15

堆排序:堆排序就是按照 大顶堆,小顶堆  的方式来进行排序,循环判断二叉树,每次循环判断得到一个值在二叉树顶端,然后依次与二叉树的最后一个值进行替换,每次替换二叉树的长度减一。

依次进行循环判断得到值然后顶端和末尾替换,从而实现了有序的排序。

思路:

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;
		}
	}
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!