选择排序之——堆排序(c/c++)

堆是一类特殊的数据结构的统称。堆在逻辑结构上可以看作为树,但是物理结构是通过顺序表来实现的。堆总是满足下列性质:

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大顶堆,根节点最小的堆叫做最小堆或小顶堆。

堆是非线性数据结构,相当于一维数组,但有两个直接后继。

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

(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)


堆排序算法:按照堆的定义建成小(大)顶堆,输出堆顶的最小(大)数,再对剩余元素重新建堆,再输出,再建堆......

    (1)初始时如何建堆?(2)如何调整剩余元素使成为一个堆?   

    问题的关键在于调整,初始建堆也可以看做是调整所有元素成为一个堆。

堆总是一个完全二叉树,而树的叶子节点自身便是一个堆,不需要调整;只有有孩子的节点才会不符合堆的要求。本文堆排序算法的数组从下标1开始,假设数组有n个数,下标自1至n,则最后一个有孩子的节点的下标是n/2(向下取整)。从最后一个有孩子的节点往前进行查找,n/2-1,n/2-2,.......,1。

比如小顶堆 13 36 24 85 47 30 53 91共8个数,8/2=4,从第四个数85开始,将它自身作为根节点来调整堆,再对第三个数24开始调整堆...直到第一个数,这样这8个数就构成了一个堆。小顶堆建好之后,第一个数便是最小的数,将它与第八个数相交换,再对前7个数调整建堆,建好之后将此时第一个数与第七个数相交换,再对前6个数建堆......

本算法通过建立小顶堆来进行排序,这样得到的输出序列为降序序列

堆排序算法的时间复杂度为o(nlogn),空间复杂度为0(1)。它是一种不稳定的排序方法。

heapAdjust函数用来调整数组使成为一个堆,如下:该数列除了arr[s]外其余数均满足堆定义,它对数列arr{s...m]进行处理,使得该数列均满足堆定义。

  void heapAdjust(int* arr, int s, int m)
  {
	  //数组arr[s...m]中除了arr[s]外其余元素均符合堆的定义,现调整arr[s]使得
	//arr[s...m]均满足堆定义
	  int i;
	  int rc = arr[s];
	  for (i = 2 * s; i <= m; i *= 2)
	  {
		  if (i < m&&arr[i] > arr[i + 1])
			  ++i;
		  if (rc<arr[i])
			  break;
		  arr[s] = arr[i];
		  s = i;
	  }
	  arr[s] = rc;
  }

完整代码如下:

  #include<iostream>
  #define N 20
  void heapSort(int* arr, int num);
  void heapAdjust(int* arr, int s, int m);
  int main()
  {
	  int a[N+1] = {-0, 3, 2, 4, 6, 7, 5, 18, 9, 0, 1,
		  16, 8, 20, 33, 28, 64, 19, 31, 30, 25 };
	  //处理下标1到20之间的数。
	  for (int i = 1; i <=N; i++)
	  {
		  std::cout << a[i] << "  ";
	  }
	  std::cout << '\n'; 
	  heapSort(a,N);
	  for (int i = 1; i <=N; i++)
	  {
		  std::cout << a[i] << "  ";
	  }
	  std::cout << '\n';
	  return 0;
  }

  void heapSort(int* arr, int num)
  {
	  //下面注释的递归处理也是可以的,但是效率不高
	  /*if (num == 1)
		  return;*/
	  int i, temp;
	  for (i = num / 2; i > 0; i--)
		  heapAdjust(arr, i, num);
	  for (i = num; i>1; i--)
	  {
		  temp = arr[i];
		  arr[i] = arr[1];
		  arr[1] = temp;
		  heapAdjust(arr, 1, i-1);
	  }
	  /*temp = arr[1];
	  arr[1] = arr[num];
	  arr[num] = temp;
	  heapSort(arr, --num);*/
  }
  void heapAdjust(int* arr, int s, int m)
  {
	  //数组arr[s...m]中除了arr[s]外其余元素均符合堆的定义,现调整arr[s]使得
	//arr[s...m]均满足堆定义
	  int i;
	  int rc = arr[s];
	  for (i = 2 * s; i <= m; i *= 2)
	  {
		  if (i < m&&arr[i] > arr[i + 1])
			  ++i;
		  if (rc<arr[i])
			  break;
		  arr[s] = arr[i];
		  s = i;
	  }
	  arr[s] = rc;
  }

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值