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

     

  • 相关阅读:
    GDUFE ACM-1093
    GDUFE ACM-1088
    GDUFE ACM-1069
    GDUFE ACM-1051
    GDUFE ACM-1049
    GDUFE ACM-1046
    GDUFE ACM-1045
    GDUFE ACM-1043
    OpenCV学习(7.12)
    OpenCV学习(7.11)
  • 原文地址:https://www.cnblogs.com/hont/p/4655384.html
Copyright © 2011-2022 走看看