菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
472
0

堆排序

原创
05/13 14:22
阅读数 12033

堆排序相对冒泡这些要复杂一些,它需要先初始化堆。.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

 

 

 

发表评论

0/200
472 点赞
0 评论
收藏