八大基本排序---堆排序、堆结构

堆排序很重要,但是更重要的是堆这个结构

堆结构:实际上是一棵完全二叉树

一个数组可以根据父结点、左子结点、右子结点的关系,脑补出一棵完全二叉树

算法1:一个数组变为大顶堆 heapInsert()

数组:2、1、3、6、0、4

(1)只有2的时候

(2) 2、1【认为完全二叉树的范围是0~1的,超过1就越界】

(3)2、1、3

3(下标2)找到自己的父结点:(2-1)/2=0

此时不满足大顶堆了,将2跟3交换

(4)2、1、3、6

6(下标3)找到它的父结点:(3-1)/2=1,发现6>1,将3位置上的数和1位置上的数交换

然后继续比较6所在的位置和它的父结点的大小

(5) 再看4位置:2、1、3、6、0

4位置的父结点是(4-1)/2=1,0(4位置)<3(1位置),继续往下

(6)再看5位置:2、1、3、6、0、4

这样每一步都会形成一个0~i的大顶堆,遍历完整个数组就形成了0~N-1的大顶堆

//一个数据插入已经是一个大顶堆的数组中,并且调整为新的大顶堆
    public static void heapInsert(int[] arr,int index) {
        while (arr[index]>arr[(index-1)/2]) {
            swap(arr, index, (index-1)/2);
            index = (index-1)/2;
        }
    }

    public static void main(String[] args) {
        int[] arr = {5,8,9,1,2} ;
        System.out.println(Arrays.toString(arr));
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        System.out.println(Arrays.toString(arr));

    }

二叉树如果结点个数为N,树的高度logN,所以每加入一个结点、调整形成一个大顶堆的时间复杂度O(logN)【只需要比较自己的那个分支】

那么一个数组中一共N个结点,一个一个加入并且形成大顶堆的时间复杂度如下:

算法2:已经形成的大顶堆里有一个数字突然变小了,重新调整这个数组形成大顶堆 heapify()

6变为1了

找到这个结点的左子结点、右子结点

左右两个结点之间先PK一下找到最大值

看左右两个结点之间的最大值比不比1大

1和5交换

再找1位置的左右孩子,找到一个最大值;如果没有左右孩子那就停住

//已经形成的大顶堆里,某一个数字(index位置的值)突然变小了,重新调整为一个大顶堆
    public static void heapify(int[] arr,int index, int heapSize){
        int left = 2*index+1;
        int largest;
        //如果当前结点的左子结点越界了,证明当前结点已经是叶结点了
        while (left<heapSize) {
            //找出左右孩子中的最大值的下标---largest
            //如果右子结点存在,那么取左右结点中的最大值;
            //如果右子结点不存在,那么取左结点就是唯一的最大值
            if (left+1<heapSize && arr[left]<arr[left+1]) {
                largest = left+1;
            }else {
                largest = left;
            }
            //父结点大于等于左右子结点中的最大值,不用动
            if (arr[index]>=arr[largest]) {
                break;
            }else {
                swap(arr, largest, index);
                index = largest;
                left = 2*index+1;
            }
        }
    }

堆排序:

(1)先把数组调整为大顶堆

(2)把堆顶元素和最后一个位置的元素做交换

这事最大的数字换到了最后,然后让堆的大小-1(heapSize--),6就相当于永远不动了

然后从0位置开始做heapify()的调整;重新调整为大根堆

-----------------à

然后再把这个堆顶元素与堆中最后一个元素交换

import java.util.Arrays;

public class HeapSort {

    public static void main(String[] args) {
        int[] arr = {5,8,9,1,2} ;
        System.out.println(Arrays.toString(arr));
        heapSort(arr);
        System.out.println(Arrays.toString(arr));

    }

    public static void heapSort(int[] arr) {
        //1.形成大顶堆
        for (int i=0; i<arr.length; i++) {
            heapInsert(arr, i);
        }
        //2.堆顶元素跟最后一个数据交换位置,堆的大小-1
        int heapSize = arr.length;
        while (heapSize>0) {
            //恢复成大顶堆
            swap(arr, 0, --heapSize);
            heapify(arr, 0, heapSize);
        }
    }

    //之前已经是一个大顶堆了,将arr[index]加入后,调整为新的大顶堆
    public static void heapInsert(int[] arr,int index){
        //找到父结点,与父结点的值比较
        while (arr[index] > arr[(index-1)/2]) {
            swap(arr, (index-1)/2, index);
            index = (index-1)/2;
        }
    }

    //已经形成的大顶堆里,某一个数字(index位置的值)突然变小了,重新调整为一个大顶堆
    public static void heapify(int[] arr,int index, int heapSize){
        int left = 2*index+1;
        int largest;
        //如果当前结点的左子结点越界了,证明当前结点已经是叶结点了
        while (left<heapSize) {
            //找出左右孩子中的最大值的下标---largest
            //如果右子结点存在,那么取左右结点中的最大值;如果右子结点不存在,那么取左结点就是唯一的最大值
            if (left+1<heapSize && arr[left]<arr[left+1]) {
                largest = left+1;
            }else {
                largest = left;
            }
            //父结点大于等于左右子结点中的最大值,不用动
            if (arr[index]>=arr[largest]) {
                break;
            }else {
                swap(arr, largest, index);
                index = largest;
                left = 2*index+1;
            }
        }
    }

    public static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

原文地址:https://www.cnblogs.com/yuange678/p/10828692.html

时间: 2024-10-28 23:05:15

八大基本排序---堆排序、堆结构的相关文章

探秘堆结构

一.概述 此处所说的堆为数据结构中的堆,而非内存分区中的堆.堆通常可以被看做是树结构,满足两个性质:1)堆中任意节点的值总是不大于(不小于)其子节点的值:2)堆是一棵完全树.正是由于这样的性质,堆又被称为优先队列.根据性质一,将任意节点不大于其子节点的堆称为最小堆或最小优先队列,反之称为最大堆或最大优先队列.优先队列在操作系统作业调度的设计中有着举足轻重的作用.之前写了一篇优先队列的文章,详见算法导论第六章优先队列. 常见的堆结构,有二叉堆.左倾堆.斜堆.二项堆.斐波那契堆等.斐波那契堆在前文算

数据结构和算法设计专题之---八大内部排序

摘要: 前几天,看到一篇前辈的博文"程序猿必知的8大排序",不禁的手痒起来,又一次翻开严蔚敏老师的<数据结构>复习了一遍,然后一一的用java去实现,当中有不足之处,还望各位道友指正出来. 先来看看8种排序之间的关系: 第一:直接插入排序 1. 基本思想:在要排序的一组数中,如果前面(n-1) [n>=2] 个数已经是排好顺序的,如今要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的.如此重复循环,直到所有排好顺序. 2. 实例 3. 用java实现 [jav

八大基础排序总结

前言 大概花了一周的时间把八大基础排序过了一遍,这篇博文主要是用来回顾一下八大基础排序的要点和一些总结- 回顾: 冒泡排序就这么简单 选择排序就这么简单 插入排序就这么简单 快速排序就这么简单 归并排序就这么简单 堆排序就这么简单 希尔排序就这么简单 基数排序就这么简单 总的来说:快速排序是用得比较广泛的一个排序,也是经常出现的一个排序,应该重点掌握- 二.八大排序总结 2.1冒泡排序 思路: 俩俩交换,大的放在后面,第一次排序后最大值已在数组末尾. 因为俩俩交换,需要n-1趟排序,比如10个数

排序 选择排序&amp;&amp;堆排序

选择排序&&堆排序 1.选择排序: 介绍:选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾.以此类推,直到所有元素均排序完毕. 步骤:假设数组array长度为N即有数组内有N个数据未排序数据 1.第一趟遍历将这N个数据中最小的数据和array[0]交换. 2.第二趟则遍历N-1个数据,将这N-1个数据中最小的和arra

排序 | 堆排序

先用一段 C++ 代码来看看推排序的过程: 1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 bool cmp(const int lhs, const int rhs) 6 { 7 return lhs > rhs; 8 } 9 10 int main() 11 { 12 int arr[] = {4, 2, 10, 9, 5, 6, 8, 6, 7, 1, 3}; 13 make

选择排序---简单选择排序 堆排序

一.简单选择排序 对于n个数要进行n次排序,第一次,将最小的数放在第一个.第二次,将第二小的树,放在第二个.... 每次都和后面的数做比较,如果是从小到大的排序,当当前的数字比后面的大时,要进行交换. #include <stdio.h> void chosesort(int a[],int length) { int i,j,temp; for(i=0;i<length;i++) for(j=i+1;j<length;j++) { if(a[i]>a[j]) { temp

SDUT 堆结构练习——合并果子之哈夫曼树(丧心病狂heap)

树-堆结构练习--合并果子之哈夫曼树 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了.多多在合并果子时总共消耗的体力等于每次合并所消耗体力之和. 因为还要花大力气把这些果子搬回家,所以

插入排序 | 冒泡排序 | 希尔排序 | 堆排序 | 快速排序 | 选择排序 | 归并排序

以下是最近学习各种算法的代码实现: #include <stdlib.h> #include <stdio.h> #include <time.h> #include <limits.h> typedef int EleType; typedef int (*CompFunc)(void *,void *); int IntComp(void * a,void *b) { if(*(int *)a > *(int *)b) return 1; if(*

C# 插入排序 冒泡排序 选择排序 高速排序 堆排序 归并排序 基数排序 希尔排序

以下列出了数据结构与算法的八种基本排序:插入排序 冒泡排序 选择排序 高速排序 堆排序 归并排序 基数排序 希尔排序,然后是測试的样例.代码位置:http://download.csdn.net/detail/luozuolincool/8040027 排序类: public class Sortings { //插入排序 public void insertSort(int[] array) { int temp = 0; int index = 0; for (int i = 0; i <