内部排序之堆排序的实现详解_C 语言

堆排序(Heap Sort)只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。
(1)基本概念
a)堆:设有n个元素的序列:
{k1, k2, ..., kn}
对所有的i=1,2,...,(int)(n/2),当满足下面关系:
                                                                  ki≤k2i,ki≤k2i+1
                                                  或            ki≥k2i,ki≥k2i+1
这样的序列称为堆。
堆的两种类型:
   根结点最小的堆----小根堆。
   根结点最大的堆----大根堆。
根结点称为堆顶,即:在一棵完全二叉树中,所有非叶结点的值均小于(或均大于)左、右孩子的值。
b)堆排序:是一种树型选择排序,特点是,在排序过程中,把R[1..n]看成是一个完全二叉树的存储结构,利用完全二叉树双亲结点和孩子结点的内在关系,在当前无序区中选择关键字最大(最小)的记录。
2)堆排序步骤:
1、从k-1层的最右非叶结点开始,使关键字值大(或小)的记录逐步向二叉树的上层移动,最大(或小)关键字记录成为树的根结点,使其成为堆。
2、逐步输出根结点,令r[1]=r[i](i=n,,n-1,...,2),在将剩余结点调整成堆。直到输出所有结点。我们称这个自堆顶到叶子的调整过程为“筛选”。
(3)要解决的两个问题:
1、如何由一个无序序列建成一个堆;
2、输出一个根结点后,如何将剩余元素调整成一个堆。
将一个无序序列建成一个堆是一个反复“筛选”的过程。若将此序列看成是一个完全二叉树,则最后一个非终端结点是第floor(n/2)个元素,由此“筛选”只需从第floor(n/2)个元素开始。
堆排序中需一个记录大小的辅助空间,每个待排的记录仅占有一个存储空间。堆排序方法当记录较少时,不值得提倡。当n很大时,效率很高。堆排序是不稳定的。
堆排序的算法和筛选的算法如第二节所示。为使排序结果是非递减有序排列,我们在排序算法中先建一个“大顶堆”,即先选得一个关键字为最大的记录并与序列中最后一个记录交换,然后对序列中前n-1个记录进行筛选,重新将它调整为一个“大顶堆”,然后将选得的一个关键字为最大的记录(也就是第一个元素)与当前最后一个记录交换(全局看是第n-1个),如此往复,直到排序结束。由到,筛选应按关键字较大的孩子结点向下进行。
堆排序的算法描述如下: 

 

用C语言代码实现如下:

复制代码 代码如下:

#include "iostream"
using namespace std;
#define MAXSIZE 20
typedef struct
{
 int key;
 //其他数据信息
}RedType;
typedef struct
{
 RedType r[MAXSIZE+1];
 int length;
}Sqlist;
typedef Sqlist HeapType;  //堆采用顺序表存储表示
void HeapAdjust(HeapType &H,int s,int m)   //已知H.r[s...m]中记录的关键字出H.r[s].key之外均满足堆的定义,本函数调整H.r[s]的关键字,使H.r[s...m]成为一个大顶堆(对其中记录的关键字而言)
{
 int j;
 RedType rc;
 rc=H.r[s];
 for(j=2*s;j<=m;j*=2)   //沿key较大的孩子结点向下筛选
 {
  if(j<m && (H.r[j].key<H.r[j+1].key))     //j为key较大的记录的下标
   ++j;
  if(rc.key>=H.r[j].key)           //rc应插入在位置s上
   break;
  H.r[s]=H.r[j];      //将左、右孩子较大的结点与父节点进行交换,建成大顶堆
  s=j;
 }
 H.r[s]=rc;             //插入
}
void HeapSort(HeapType &H)      //对顺序表H进行堆排序
{
 int i;
 for(i=H.length/2;i>0;--i)   //由一个无序序列建成一个大顶堆,将序列看成是一个完全二叉树,则最后一个非终端节点是第n/2个元素
  HeapAdjust(H,i,H.length);
 for(i=H.length;i>1;--i)
 {
  H.r[0]=H.r[1];   //将堆顶记录和当前未经排序的子序列H.r[1...i]中最后一个记录相互交换
  H.r[1]=H.r[i];
  H.r[i]=H.r[0];
  HeapAdjust(H,1,i-1);    //将H.r[1...i-1]重新调整为大顶堆
 }
}//HeapSort
void InputL(Sqlist &L)
{
 int i;
 printf("Please input the length:");
 scanf("%d",&L.length);
 printf("Please input the data needed to sort:\n");
 for(i=1;i<=L.length;i++)    //从数组的第1个下标开始存储,第0个下标作为一个用于交换的临时变量
  scanf("%d",&L.r[i].key);
}
void OutputL(Sqlist &L)
{
 int i;
 printf("The data after sorting is:\n");
 for(i=1;i<=L.length;i++)
  printf("%d ",L.r[i].key);
 printf("\n");
}
int main(void)
{
 Sqlist H;
 InputL(H);
 HeapSort(H);
 OutputL(H);
 system("pause");
 return 0;
}

不使用上面的结构体的另外一种方法如下:

复制代码 代码如下:

/*
*堆排序
*/
#include "iostream"
using namespace std;
#define N 10
int array[N];
void man_input(int *array)
{
 int i;
 for(i=1;i<=N;i++)
 {
  printf("array[%d]=",i);
  scanf("%d",&array[i]);
 }
}
void mySwap(int *a,int *b)//交换
{
 int temp;
 temp=*a;
 *a=*b;
 *b=temp;
}
void heap_adjust(int *heap,int root,int len)     //对堆进行调整,使下标从root到len的无序序列成为一个大顶堆
{
 int i=2*root;
 int t=heap[root];
 while(i<=len)
 {
  if(i<len)
  {
   if(heap[i]<heap[i+1])
    i++;
  }
  if(t>=heap[i])
   break;
  heap[i/2]=heap[i];
  i=2*i;
 }
 heap[i/2]=t;
}
void heapSort(int *heap,int len)      //堆排序
{
 int i;
 for(i=len/2;i>0;i--)    //由一个无序序列建成一个大顶堆,将序列看成是一个完全二叉树,则最后一个非终端节点是第len/2个元素
 {
  heap_adjust(heap,i,len);
 }
 for(i=len;i>=1;i--)
 {
  mySwap(heap+i,heap+1);    //将堆顶记录与最后一个记录相互交换
  heap_adjust(heap,1,i-1);   //将下标为1~i-1的记录重新调整为大顶堆
 }
}
void print_array(int *array,int n)
{
 int k;
 for(k=1;k<n+1;k++)
 {
  printf("%d\t",array[k]);
 }
}
int main(void)
{
 man_input(array);
 heapSort(array,N);
 printf("\nAfter sorted by the heap_sort algorithm:\n");       
 print_array(array,N);   //打印堆排序结果
 system("pause");
 return 0;
}

时间: 2024-10-29 09:06:35

内部排序之堆排序的实现详解_C 语言的相关文章

C语言 经典题目螺旋矩阵 实例详解_C 语言

C语言 经典题目螺旋矩阵 //N阶螺旋矩阵 #include <stdio.h> #include <stdlib.h> int main() { int N,i,j,n,num=1; int a[10][10]={0}; printf("输入你要输出的几阶中断:"); scanf("%d",&N); for(n=0;n<=N/2;n++) { for(j=n;j<=N-n-1;j++) a[n][j]=num++; fo

C++计数排序详解_C 语言

计数排序不同于比较排序,是基于计数的方式,对于计数排序,假设每一个输入都是介于0~k之间的整数.对于每一个输入元素x,确定出小于x的元素的个数.假如有17个元素小于x,则x就属于第18个输出位置. 计数排序涉及到三个数组A[0-..length-1],length为数组A的长度:数组B与数组A长度相等,存放最终排序的结果:C[0-..K]存放A中每个元素的个数,k为数组A中的最大值. int count_k(int A[],int length),此函数为了确定数组A中最大的元素,用来确定C数组

C语言实现排序算法之归并排序详解_C 语言

排序算法中的归并排序(Merge Sort)是利用"归并"技术来进行排序.归并是指将若干个已排序的子文件合并成一个有序的文件. 一.实现原理: 1.算法基本思路 设两个有序的子文件(相当于输入堆)放在同一向量中相邻的位置上:R[low..m],R[m+1..high],先将它们合并到一个局部的暂存向量R1(相当于输出堆)中,待合并完成后将R1复制回R[low..high]中. (1)合并过程 合并过程中,设置i,j和p三个指针,其初值分别指向这三个记录区的起始位置.合并时依次比较R[i

Windows程序内部运行机制实例详解_C 语言

本文以孙鑫老师VC++教程中的程序为基础,详细讲解了Windows程序内部运行机制,相信可以帮助大家更好的理解Windows程序运行原理及相应的VC++程序设计.具体内容如下: 创建一个Win32应用程序步骤: 1.编写WinMain函数; 2.创建窗口(步骤如下):  a.设计(一个)窗口类(WNDCLASS)  b.注册(该)窗口类.  c.创建窗口.  d.显示并更新窗口. 3.编写消息循环. 4.编写窗口过程函数. //WinMain.cpp #include <windows.h>

浅谈c++中的stl中的map用法详解_C 语言

Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道.这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处. 下面举例说明什么是一对一的数据映射.比如一个班级中,每个学生的学号跟他的姓名就存在着一一

深入内存对齐的详解_C 语言

1.引子     在结构中,编译器为结构的每个成员按其自身的自然对界(alignment)条件分配空间.各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同.     例如,下面的结构各成员空间分配情况(假设对齐方式大于2字节,即#pragma pack(n), n = 2,4,8...下文将讨论#pragmapack()): 复制代码 代码如下: struct test {     char x1;     short x2;     float x3;    

C++设计模式编程之Flyweight享元模式结构详解_C 语言

由遇到的问题引出享元模式: 在面向对象系统的设计何实现中,创建对象是最为常见的操作.这里面就有一个问题:如果一个应用程序使用了太多的对象,就会造成很大的存储开销.特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为没有字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费.例如一个字母"a"在文档中出现了100000 次,而实际上我们可以让这一万个字母"a"共享一个对象,当然因为在不同的位置可能字母"a"有不

C++联合体union用法实例详解_C 语言

本文实例讲述了C++联合体union用法.分享给大家供大家参考.具体如下: 我们应该按照C中的convention去使用union,这是我这篇文章要给出的观点.虽然C++使得我们可以扩展一些新的东西进去,但是,我建议你不要那样去做,看完这篇文章之后,我想你大概也是这么想的. C由于没有类的概念,所有类型其实都可以看作是基本类型的组合,因此在union中包含struct也就是一件很自然的事情了,到了C++之后,既然普遍认为C++中的struct与class基本等价,那么union中是否可以有类成员

C++智能指针实例详解_C 语言

本文通过实例详细阐述了C++关于智能指针的概念及用法,有助于读者加深对智能指针的理解.详情如下: 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见. 用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::scoped_ptr.boost::shared_p