堆排序简要介绍

来源:互联网 发布:神话特效软件 编辑:程序博客网 时间:2024/05/17 09:35

堆排序

堆是完全二叉树,具有如下性质:大顶堆:每个节点的值大于或等于其左右孩子结点的值,小顶堆:每个节点的值都小于或等于其左右孩子结点的值。
堆排序是根据完全二叉树的性质5来排序的。
完全二叉树性质五
1.如果i=1,则结点i是二叉树的根,无双亲,如果i>1,则其双亲是结点i/2
2.如果2*i>n,则结点i无左孩子,否则其左孩子是结点2*i
3.如果2*i+1>n,则该结点i无右孩子,否则其右孩子是结点2*i+1
堆排序的思想是,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点,将它移走,此时末尾元素就是最大值,然后将剩下的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值,如此反复,便能得到一个有序序列了。
程序思路
1.将无序序列构建一个大顶堆。
2.将第一个元素和最后一个元素交换,将前n-1个元素重新构建大顶堆
3.循环往复,直到排序完成。
整体代码:

void Heap_sort(sqlist* l){    assert(l!=NULL);    int i;    for(i=l->length/2;i>0;--i)    {        Heap(l,i,l->length);    }    for(i=l->length;i>1;--i)    {        swap(l,1,i);        Heap(l,1,i-1);    }

构建大顶堆代码

void Heap(sqlist* l,int fi,int la){    int tmep,i;    temp=l->data[fi];    for( i=fi*2;i<la;i*=2)    {        if(i<la&&l->data[i]<l->data[i+1])        {            ++i;        }        if(temp>l->data[j])        {        break;        }        l->data[fi]=l->data[i];        fi=j;    }    l->data[fi]=temp;}

大顶堆代码解释:
1.输入参数为链表,起始位置,结束位置(一般为链表长队或顺序表长度)。
2.循环开始是从起始位置的左孩子开始,判断左右孩子哪个大,找到最大,用最大值和其父节点进行比较。
3.若孩子结点大,将该孩子结点的值赋值给双亲结点,并且将最大孩子结点的位置赋值给根节点,令其为根节点,再循环判断该根节点下的最大孩子结点。否则,跳出循环。
4.最终,将初始值赋值给交换位置后的点。
注意点:
1.在进行左右孩子结点比较时,一定要确保左右孩子结点存在。即左右孩子的坐标点不能超过链表或者顺序表的长度。
2.在查找下一级的最大/最小结点时,一定要判断该级结点的孩子结点在链表长度范围内。
3.赋值的时候是对最终改变了位置的点赋值。

顺序表的堆排序实现(小顶堆)

#define HeapElem  intvoid FilterDown(HeapElem* ar, int pos, int end){    int temp = ar[pos];    int i = pos;    int j = 2 * pos + 1;    while (j< end)    {        if (j + 1 <= end && ar[j] > ar[j + 1])            j += 1;        if (temp <= ar[j])            break;        ar[i] = ar[j];        i = j;        j = i * 2 + 1;    }    ar[i] = temp;}void swap(HeapElem* a, HeapElem* b){    int temp = *a;    *a = *b;    *b = temp;}void main(){    int arr[10] = { 12, 23, 34, 45, 56, 67, 78, 89, 90, 2 };    int len = sizeof(arr) / sizeof(arr[0]);    int pos = 0;    while (pos!=(len-1))    {        FilterDown(arr, 0, len-1-pos);        swap(&arr[0], &arr[len - pos - 1]);        ++pos;    }    for (int i = 0; i < len; ++i)    {        printf("%4d", arr[i]);    }}

注意:这里有一个问题有待解决,2这个数字的排序是错误的,造成它错误的原因为,我们没有首先构造出一个小顶堆,所以它在排序时就发生了错误,所以更改时应该先从数组中间开始,向头部遍历,依次构建出一个小顶堆,再对构造好的小顶堆进行排序。
根据以上结论,我重新构建了一下,但还是没有解决问题!!!

void main(){    int arr[10] = { 12,23, 34, 45, 56, 67, 78, 89, 90,2};    int len = sizeof(arr) / sizeof(arr[0]);    int pos = 0;    for (int i = len / 2; i > 0; --i)    {        FilterDown(arr, i, len - 1);    }    while (pos!=(len-1))    {        FilterDown(arr, 0, len-1-pos);        swap(&arr[0], &arr[len - pos - 1]);        ++pos;    }    for (int i = 0; i < len; ++i)    {        printf("%4d", arr[i]);    }}

还需要思考,来解决这个问题。

原创粉丝点击