zoukankan      html  css  js  c++  java
  • 堆排序

    堆排序相对冒泡这些要复杂一些,它需要先初始化堆。.net里List的排序就混合使用了堆排序和另2种排序

    出于学习目的,代码示范里不使用数组结构,数组取索引比较深涩。而使用嵌套类来实现。

    1.初始化堆


    排序肯定是有升序和降序两种,堆排序也一样,分为大顶堆和小顶堆。初始化堆的目的就是变为大顶堆或者小顶堆

    传统的方法是取数组下标[n/2]向下取整,但直接取最后一个元素往前遍历也是可行的

    下面用22,44,6,88,5几个数作为示范

    step1.默认的树结构

    step2.自顶向下,以22开始先比较44和6两个子树,比较方式可以先比较左子树和右子树,取最大的值再和父节点比较。

    44和6先进行比较,44比较大。然后44再和22进行比较,发现比父节点大。然后执行交换

    step3.然后比较22的两个子树,88比较大,执行交换

    step4.由于内部执行了交换,再次进行遍历。发现88比44大,执行交换。

    至此,初始化堆完成

    2.执行排序


    堆排序有一个有序区和无序区的概念,有序区同样在堆中,但是不参与排序。只有无序区参与排序,排序结果转移到有序区。

    直到无序区没有之后,排序结束

    step1.是初始化好的堆,没有进行任何操作

    step2.需要不断的把第一个元素和最后一个元素进行交换,放入有序区,橙色的是有序区

    step3.交换完成之后,再重复进行初始化堆,进行调整

    step4.由于88是有序区的内容,所以只和左子树22比较后,进行交换。

    step5.再次和第一个元素进行交换,加入到有序区。

    堆排序完成

    下面附上代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Hont
    {
        public class HeapSort
        {
            public class Node
            {
                /// <summary>
                /// 用了一下空对象模式,省去了判断null
                /// </summary>
                public readonly static Node EMPTY_NODE;
    
                public Node LeftChild { get; set; }
                public Node RightChild { get; set; }
                public Node Parent { get; set; }
                public int Value { get; set; }
                public bool IsUsed { get; set; }
    
    
                static Node()
                {
                    EMPTY_NODE = new Node() { Value = 0, IsUsed = true };
                }
    
                public Node()
                {
                    LeftChild = EMPTY_NODE;
                    RightChild = EMPTY_NODE;
                }
    
                public Node(Node parent)
                    : this()
                {
                    this.Parent = parent;
                }
            }
    
            /// <summary>
            /// 执行排序
            /// </summary>
            /// <param name="sourceArray">原始数组</param>
            /// <param name="maxOrMin">降序还是升序</param>
            /// <returns>排序后的数组</returns>
            public int[] Sort(int[] sourceArray, bool maxOrMin = true)
            {
                Func<int, int, bool> compare = null;
                if (maxOrMin)
                    compare = (a, b) => a > b;
                else
                    compare = (a, b) => a < b;
    
                var rootNode = BuildHeap(sourceArray.ToList());
                AdjustHeap(rootNode, compare);
                SortHeap(rootNode, compare);
                return OutputHeap(rootNode).ToArray();
            }
    
            /// <summary>
            /// 构建堆,因为没有用数组去实现,需要额外构建
            /// </summary>
            Node BuildHeap(List<int> sourceList)
            {
                Node result = new Node();
                List<Node> nextDepthNodeList = new List<Node>();
                List<Node> tmpNextDepthNodeList = new List<Node>();
    
                BuildHeap(result, sourceList, nextDepthNodeList);
    
                for (int i = 0; i < nextDepthNodeList.Count; i++)
                {
                    var item = nextDepthNodeList[i];
                    if (!BuildHeap(item, sourceList, tmpNextDepthNodeList))
                    {
                        break;
                    }
    
                    if (i - 1 == nextDepthNodeList.Count)
                    {
                        nextDepthNodeList = tmpNextDepthNodeList;
                        tmpNextDepthNodeList.Clear();
                        i = 0;
                    }
                }
    
                var lastNode = GetLastSortNode(result);
                result.Value = lastNode.Value;
                if(lastNode.Parent.LeftChild == lastNode)
                {
                    lastNode.Parent.LeftChild = Node.EMPTY_NODE;
                }
                else
                {
                    lastNode.Parent.RightChild = Node.EMPTY_NODE;
                }
    
                return result;
            }
    
            bool BuildHeap(Node currentNode, List<int> sourceList, List<Node> nextDepthNodeList)
            {
                if (sourceList.Count < 1) return false;
    
                var firstNode = sourceList[0];
                currentNode.LeftChild = new Node(currentNode) { Value = firstNode };
                nextDepthNodeList.Add(currentNode.LeftChild);
                sourceList.RemoveAt(0);
    
                if (sourceList.Count > 0)
                {
                    var lastNode = sourceList[sourceList.Count - 1];
                    currentNode.RightChild = new Node(currentNode) { Value = lastNode };
                    nextDepthNodeList.Add(currentNode.RightChild);
                    sourceList.RemoveAt(sourceList.Count - 1);
                }
    
                return true;
            }
    
            /// <summary>
            /// 调整堆,调整至大顶堆或小顶堆,依据第二个参数
            /// </summary>
            void AdjustHeap(Node heap, Func<int, int, bool> compare)
            {
                if (heap == Node.EMPTY_NODE) return;
    
                if (heap.LeftChild.IsUsed && heap.RightChild.IsUsed) return;
    
                var leftChild = heap.LeftChild;
                var rightChild = heap.RightChild;
                var leftChildValue = heap.LeftChild.Value;
                var rightChildValue = heap.RightChild.Value;
    
                if (leftChild.IsUsed) leftChildValue = compare(int.MinValue, int.MaxValue) ? int.MaxValue : int.MinValue;
                if (rightChild.IsUsed) rightChildValue = compare(int.MinValue, int.MaxValue) ? int.MaxValue : int.MinValue;
    
                var selectChild = compare(leftChildValue, rightChildValue) ? leftChild : rightChild;
                var flag = compare(selectChild.Value, heap.Value);
                if (flag)
                {
                    var tmp = heap.Value;
                    heap.Value = selectChild.Value;
                    selectChild.Value = tmp;
                }
    
                AdjustHeap(heap.LeftChild, compare);
                AdjustHeap(heap.RightChild, compare);
    
                if (flag)
                {
                    AdjustHeap(heap, compare);
                }
            }
    
            void SortHeap(Node root, Func<int, int, bool> compare)
            {
                while (!root.IsUsed)
                {
                    var lastNode = GetLastSortNode(root);
                    var tmpHeapValue = root.Value;
                    root.Value = lastNode.Value;
                    lastNode.Value = tmpHeapValue;
    
                    lastNode.IsUsed = true;
                    AdjustHeap(root, compare);
                }
            }
    
            /// <summary>
            /// 获得最后可用的堆成员,如果是IsUsed说明是有序区就跳过,主要用于排序时,首尾成员交换
            /// </summary>
            Node GetLastSortNode(Node root)
            {
                Node result = root;
                while (true)
                {
                    if (result.RightChild != Node.EMPTY_NODE && !result.RightChild.IsUsed)
                    {
                        result = result.RightChild;
                    }
                    else if (result.LeftChild != Node.EMPTY_NODE && !result.LeftChild.IsUsed)
                    {
                        result = result.LeftChild;
                    }
                    else
                    {
                        break;
                    }
                }
    
                return result;
            }
    
            /// <summary>
            /// 遍历节点
            /// </summary>
            void ForeachNode(Node root, Action<Node> foreachContent)
            {
                if (root != Node.EMPTY_NODE)
                {
                    foreachContent(root);
                }
    
                if (root.LeftChild != Node.EMPTY_NODE)
                {
                    ForeachNode(root.LeftChild, foreachContent);
                }
    
                if (root.RightChild != Node.EMPTY_NODE)
                {
                    ForeachNode(root.RightChild, foreachContent);
                }
            }
    
            List<int> OutputHeap(Node root)
            {
                List<int> result = new List<int>();
    
                ForeachNode(root, m => m.IsUsed = false);
    
                while (!root.IsUsed)
                {
                    var tmpNode = GetLastSortNode(root);
                    result.Add(tmpNode.Value);
                    tmpNode.IsUsed = true;
                }
    
                return result;
            }
        }
    }
    Heap Sort

    调用:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Hont;
    
    namespace HeapSortPackage
    {
        class Program
        {
            static void Main(string[] args)
            {
                HeapSort heapSort = new HeapSort();
                var result = heapSort.Sort(new int[] { 22, 44, 88, 5, 6 }, true);
    
                Console.WriteLine(string.Join(",", result));
                Console.Read();
            }
        }
    }
    View Code

     

  • 相关阅读:
    Ubuntu 16 安装redis客户端
    crontab 参数详解
    PHP模拟登录发送闪存
    Nginx配置端口访问的网站
    Linux 增加对外开放的端口
    Linux 实用指令之查看端口开启情况
    无敌的极路由
    不同的域名可以指向同一个项目
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
    Redis 创建多个端口
  • 原文地址:https://www.cnblogs.com/hont/p/4655384.html
Copyright © 2011-2022 走看看