[数据结构与算法]堆排序 Heap Sort

来源:互联网 发布:企业名录搜索软件 编辑:程序博客网 时间:2024/06/05 08:21

堆的定义

  n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆。

  情形1:k<= k2i 且k<= k2i+1 最小化堆小顶堆

  情形2:k>= k2i 且k>= k2i+1 (最大化堆大顶堆

  其中i=1,2,…,n/2向下取整;

     

                 

 

  若将和此序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值

  由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

  例如,下列两个序列为堆,对应的完全二叉树如图:

  

 

  若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素的次小值。如此反复执行,便能得到一个有序序列,这个过程称之为堆排序

  堆排序(Heap Sort)只需要一个记录元素大小的辅助空间(供交换用),每个待排序的记录仅占有一个存储空间。

 

堆的存储

  一般用数组来表示堆,若根结点存在序号0处, i结点的父结点下标就为(i-1)/2。i结点的左右子结点下标分别为2*i+12*i+2

  (注:如果根结点是从1开始,则左右孩子结点分别是2i和2i+1。)

  如第0个结点左右子结点下标分别为1和2。

  如最大化堆如下:

   

  左图为其存储结构,右图为其逻辑结构。

存储在堆内的数据由Node类来构建。

    public class Node    {        public int data;        public Node(int key)         {            data = key;        }    }
通过吧节点插入到堆数组内的方式可以构造堆,二堆数组的元素就是堆的节点。

这里始终要把新节点放置在数组末尾的空元素内。问题是这样做很可能会打破堆的构造条件,因为新的节点的数据值可能会大于他上面某些节点值。为了把数组恢复到正确的堆构造条件,需要把新节点向上移动,一直要把它移动到数组内合适的位置上为止。用ShifUp来实现。

     public void ShifUp(int index)         {            int parent = (index - 1) / 2;            Node bottom = heapArray[index];            while ((index > 0) && heapArray[index].data < bottom.data)             {                heapArray[index] = heapArray[parent];                index = parent;                parent = (parent - 1) / 2;            }            heapArray[index] = bottom;        }
下面是Insert方法的实现代码:

        public bool Insert(int key)         {            if (currSize == maxSize)                return false;            heapArray[currSize] = new Node(key);            currSize++;            return true;        }
    这里会把新节点添加到数组的末尾。这样做会立刻打破堆构造的条件,所以通过shifup方法来找到新节点在数组内的正确位置。次方法的参数就是新节点的索引。方法的第一行会计算此节点的父节点。接着方法会把新节点保存到一个名为bottom的Node变量内。随后,wihle循环会找到新节点的正确位置。方法的最后一行会把新节点从临时放置的变量bottom内复制到数组中正确的位置上。

从堆中移除掉节点始终意味着删除最大值的节点。这是很容易实现的,因为最大值始终在根节点上。问题是一旦移除根节点,堆就不完整了,就需要对其进行重组。下面这个算法用于使堆再次完整。

(1)移除根节点

(2)把最后位置上的节点移动到根上

(3)把最后的节点向下移动,知道它在底下为止。

当连续应用这个算法的时候,就会按照排列顺序把数据从堆中移除掉。下面就是Remove方法和TrickleDown方法的实现代码。

        public Node Remove()         {            Node root = heapArray[0];            currSize--;            heapArray[0] = heapArray[currSize];            ShifDown(0);            return root;        }        public void ShifDown(int index)         {            int largerChild;            Node top = heapArray[index];            while (index < (int)(currSize / 2))             {                int leftChild = 2 * index + 1;                int rightChild = leftChild + 1;                if ((rightChild < currSize) && heapArray[leftChild].data < heapArray[rightChild].data)                {                    largerChild = rightChild;                }                else                 {                    largerChild = leftChild;                }                if (top.data >= heapArray[largerChild].data)                 {                    break;                }                                   heapArray[index] = heapArray[largerChild];                index = largerChild;            }            heapArray[index] = top;        }
完整:

    class Heap    {        Node[] heapArray = null;        private int maxSize = 0;        private int currSize = 0;        public Heap()         {        }        public Heap(int maxSize)         {            this.maxSize = maxSize;            heapArray = new Node[maxSize];        }        public bool InsertAt(int pos, Node nd)         {            heapArray[pos] = nd;            return true;        }        public void ShowArray()         {            for (int i = 0; i < maxSize; i++)             {                if (heapArray[i] != null)                 {                    System.Console.Write(heapArray[i].data+" ");                }            }        }        public void ShifUp(int index)         {            int parent = (index - 1) / 2;            Node bottom = heapArray[index];            while ((index > 0) && heapArray[index].data < bottom.data)             {                heapArray[index] = heapArray[parent];                index = parent;                parent = (parent - 1) / 2;            }            heapArray[index] = bottom;        }        public bool Insert(int key)         {            if (currSize == maxSize)                return false;            heapArray[currSize] = new Node(key);            currSize++;            return true;        }        public Node Remove()         {            Node root = heapArray[0];            currSize--;            heapArray[0] = heapArray[currSize];            ShifDown(0);            return root;        }        public void ShifDown(int index)         {            int largerChild;            Node top = heapArray[index];            while (index < (int)(currSize / 2))             {                int leftChild = 2 * index + 1;                int rightChild = leftChild + 1;                if ((rightChild < currSize) && heapArray[leftChild].data < heapArray[rightChild].data)                {                    largerChild = rightChild;                }                else                 {                    largerChild = leftChild;                }                if (top.data >= heapArray[largerChild].data)                 {                    break;                }                                   heapArray[index] = heapArray[largerChild];                index = largerChild;            }            heapArray[index] = top;        }        public void Test()         {            const int SIZE = 9;            Heap aHeap = new Heap(SIZE);            Random RandomClass = new Random();            for (int i = 0; i < SIZE; i++)             {                int rn = RandomClass.Next(1,100);                aHeap.Insert(rn);            }            Console.Write("Random: ");            aHeap.ShowArray();            Console.WriteLine();            Console.Write("Heap: ");            for(int i=(int)SIZE/2-1;i>=0;i--)            {                aHeap.ShifDown(i);            }            aHeap.ShowArray();            for (int i = SIZE - 1; i >= 0; i--)             {                Node bigNode = aHeap.Remove();                aHeap.InsertAt(i,bigNode);            }            Console.WriteLine();            Console.Write("Sorted: ");            aHeap.ShowArray();        }    }










0 0
原创粉丝点击