堆排序—顺序排序

目录

1、什么是堆?

2、堆排序

 3、案例

1、什么是堆?

堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于等于其左右孩子结点的值,称为小顶堆!

2、堆排序

堆排序算法就是利用堆(小顶堆或者大顶堆)进行排序的方法。

将待排序的序列构造成一个大顶堆,此时整个序列的最大值就是根节点。将它移走(跟堆的最后一个元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,便能得到一个有序序列了。

大顶堆排序成小顶堆:先把数据构造成一个大顶堆或小顶堆的完全二叉树,假设构造成如图1所示的大顶堆,根结点的值定为最大值,将20和90调换位置,假设数据的个数为n个,此前数据组成为完全二叉树,移走以后就不是完全二叉树,如图2所示,将剩余的n-1个值重新进行排列,再次排列成一个大顶堆,如图3所示,最后一个值就不算在内,其已经是最大值;再把80和30调换,将剩余的n-2个值重新进行排列,再次构造成大顶堆,把最大值放在后面,将剩下的值继续构造成大顶堆,一直到大顶堆里剩最后一个值,那这个值一定是最小值。

 3、案例

将系列数据进行大顶堆排序

 使用顺序结构进行存储,把一个无序的完全二叉树构造成一个大顶堆,先从最小的子树开始,每个叶子结点也是一个子树(8,9等单独结点),(4,8,9组成的也是子树),8结点也是子树,可以是大顶堆或者小顶堆,但是没有排序的必要,至少从有1个叶子的结点的子树开始,把所有有子结点的结点都遍历完,有子结点时才可以有比较。如4,从4开始,一直遍历到1,遍历到4,把(4,8,9)构造成一个大顶堆做比较,把最大值放到4的位置,从下往上开始,再把(3,6,7)构造成大顶堆作比较,把最大值放到3的位置,再把(4,2,5)构造成大顶堆,此时就和(4,8,9)有一定关系,4是里面最大的,取4,2,5中最大的值放在2的位置,如果5是最大的,那么5和2交换,如果4是最大的,4和2交换,那么2,8,9中2就不一定是最大的,2反过来后要继续遍历往下移动,和下面两个做比较,如果发现有比它更大的,则2往下移。(注:上述中数字为数据的编号)

实现的代码:添加Test脚本挂载

/****************************************************
 *  功能:堆排序—顺序存储   序号代表编号   For循环步骤:
 * 1、判断(4,8,9)i=4,maxNodeNumber=4,tempI=4,8>4,maxNodeNumber=8,8>9,最大编号还是8,maxNodeNumber!=tempI,4、8数据调换,maxNodeNumber=tempI=8,再次循环,不成立跳出循环
 * 2、判断(3,6,7)i=3,maxNodeNumber=3,tempI=3,6不大于3,7不大于3,maxNodeNumber=tempI跳出循环
 * 3、判断(2,4,5)i=2,maxNodeNumber=2,tempI=2,4>2,maxNodeNumber=4,5>4,maxNodeNumber=5,maxNodeNumber!=tempI,2、5数据调换,maxNodeNumber=tempI=5,再次循环,不成立跳出循环
 * 4、判断(1,2,3)i=1,maxNodeNumber=1,tempI=1,2>1,maxNodeNumber=2,3>2,maxNodeNumber=3,1、3数据调换,maxNodeNumber=tempI=3,再次循环判断(3,6,7),6<3,7>3,maxNodeNumber=7,3、7数据调换
 * 循环结束,数据排序成大顶堆
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    int[] date = { 50, 10, 90, 30, 70, 40, 80, 60, 20 };//存储开始的无序数据
    void Start()
    {
        HeadSort(date);
        foreach (int i in date)
        {
            Debug.Log(i + " ");
        }
    }
    /// <summary>
    /// 从最小的堆开始遍历,最小的堆构造成大顶堆,遍历所有的非叶子结点,最末的叶子结点的父亲肯定就是最后一个有子结点的最小的子树
    /// 编号:n(9) 末叶的父亲:(n/2-1)(4)  末叶父类左子结点:(n-1)(8)    末叶父类右子结点(9)
    /// 遍历从最后一个非子结点到1号    编号为案例的编号
    /// </summary>
    /// <param name="date"></param>
    public static void HeadSort(int[] date) //传递排序的数组
    {
        //遍历这个数的所有非叶结点,挨个把所有的子树,变成大顶堆   date.lengte/2:非子结点(4)
        for (int i = date.Length / 2; i >= 1; i--) 
        {
            HeapAjust(i,date,date.Length);
            //经过上面的方法,是把二叉树变成大顶堆
        }
        //利用大顶堆的方法对数据组进行堆排序
        //首末数据交换,把剩余的再次构造成大顶堆,再交换,再构造,如此循环,直到i=1,循环结束
        for (int i = date.Length; i > 1; i--) //i从最后一个数据开始,跟第一个数据进行交换,然后--循环,不需要=1,=1时就不需要排序
        {
            //把编号1和编号i位置交换,交换结束1位置存储最小值,i位置存储最大值
            //1到(i-1)构造成大顶堆,再次位置交换
            int temp1 = date[0]; //临时存储第一个数据
            date[0] = date[i - 1]; //最后一个数据交换给第一个数据的位置
            date[i - 1] = temp1; //第一个数据交换给最后一个数据的位置
            HeapAjust(1,date,i-1);
        }
    }
    //堆调整
    private static void HeapAjust(int numberToAjust,int[]date,int maxNumber)//将要调整的结点,调整的数组,堆的最大编号
    {
        //从根结点开始,用根结点和下面的子结点做比较,找有没有比根结点大的,找到之后做交换,再次比较,一直到下面的没有比根结点大的
        int maxNodeNumber = numberToAjust; // 4 最大结点的编号   结点里面编号最大
        int tempI = numberToAjust; //如 4  和左右子结点做比较  
        while (true)
        {
            //把i结点的子树变成大顶堆
            int leftChildNumber = tempI * 2; // 如 8  左子结点编号
            int rightChildNumber = leftChildNumber + 1; // 如 9 右子结点编号
            //leftChildNumber <= date.Length判断左孩子编号是否存在   
            //date[leftChildNumber - 1] > date[maxNodeNumber - 1]数据大于最大结点编号的数据   索引=编号-1
            if (leftChildNumber <= maxNumber &&
                date[leftChildNumber - 1] > date[maxNodeNumber - 1]) //60>30   60和30做调换
            {
                maxNodeNumber = leftChildNumber; //找到最大左子结点对应的编号
            }
            if (rightChildNumber <= maxNumber && date[rightChildNumber - 1] > date[maxNodeNumber - 1])
            {
                maxNodeNumber = rightChildNumber; //找到最大右子结点对应的编号
            }
            if (maxNodeNumber != tempI) //发现了一个比i更大的子结点,交换i和maxNodeNumber里面的数据
            {
                int temp = date[tempI - 1];
                date[tempI - 1] = date[maxNodeNumber - 1];
                date[maxNodeNumber - 1] = temp;
                tempI = maxNodeNumber;
            }
            else //子结点没有比它更大   终止
            {
                break;
            }
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值