C语言实现堆排序

        堆排序利用堆的性质来对数组进行排序,也就是说它的所有操作都是在数组上进行的,类似于树状数组的形式;并不是通过实际上的二叉树排序。

        要实现堆排序,首先需要了解堆排序的原理。

堆排序原理:       

  1. 堆的结构类似于完全二叉树,头节点位于整个结构的最上方,每个父节点从左到右依次分岔,延申出两个子节点。
  2. 每层节点从左到右在数据中是依次排列的关系。
  3. 堆中某个结点的值总是不大于其父结点的值(大顶堆:头节点值最大)。

  4. 堆中某个结点的值总是不小于其父结点的值(小顶堆:头节点值最小)。

        因为是排序算法,所以这里不用二叉树结构实现堆结构,使用数组模拟并将其想象成一棵树:

        arr = { 0, 1, 2, 3, 4, 5, 6 };

C语言实现堆排序_第1张图片

        上图的每个位置分别对应一个数组的元素下标

HeapInsert:(末尾插入)

        假设这个堆有序,且每个父节点的值大于等于其子节点(大顶堆):

C语言实现堆排序_第2张图片

        假如上图是一个数组arr,想要在该数组末尾插入一个数字10,并且变更数组元素的顺序使得堆结构依然成立。

C语言实现堆排序_第3张图片

  • 我们只需要遵守堆结构的基本顺序进行比较排序即可

        因为 堆中某个结点的值总是不大于或不小于其父结点的值,所以需要将2位置(8)和6位置(10)进行比较,当子节点的数值大于父节点,则该子节点和父节点进行交换,即8 与 10 交换。

        C语言实现堆排序_第4张图片

         完成上个步骤,将需要操作的光标变成位置2(10),继续与其父节点位置0(9)进行比较,若大于其父节点,则交换,否则跳出循环。到这里一个插入操作结束。

        代码如下:

void Swap(int *arr, int x, int y)
{
	int temp = 0;
	temp = arr[x];
	arr[x] = arr[y];
	arr[y] = temp;
}

void HeapInsert(int *arr, int index)
{
	while (arr[index] > arr[(index - 1) / 2])
	{
		//交换函数swap
		Swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;
	}
}

HeapIfy:(中间插入向下比较)

        假设对刚才的数组首元素进行变更,那么要如何使该数组保持堆数组

        若将首元素替换为7,则需要如何进行变动?C语言实现堆排序_第5张图片

  • 第一步:找出子节点中较大的数字。
  • 第二步:父节点与子节点中较大的数字比较,找出较大值,若父节点较大,则跳出循环。若子节点较大,则父节点和子节点交换。
  • 第三步:光标跳转至被交换子节点。C语言实现堆排序_第6张图片

        重复该过程,即可得到新数组

        代码入下:

/*
arr: 目标数组
index: 目标节点
size: 数组大小监测
*/
void HeapIfy(int *arr, int index, int size)
{
	int left = index * 2 + 1;
	while (left < size)
	{
		//找较大子节点
		int largest = (left + 1 < size && arr[left + 1] > arr[left]) ? left + 1 : left;

		//比较子节点和父节点
		if (arr[largest] > arr[index])
			Swap(arr, largest, index);
		else
			break;

		//循环结构
		index = largest;
		left = index * 2 + 1;
	}
}

堆排序:

  • 堆排序的实质就是调用上述两种方法
  • 先将数据全部写入二叉树;
  • 取出头节点的值(最大值),将这个最大值与数组最后一位交换,这样最大值就排在了最后一位,光标前移,不再将最后一位算入堆结构中;
  • 排除最后一位的元素,对前size - 1位进行HeapIfy(中间插入向下比较),得到新的顺序;
  • 重复这个操作,当size == 0即可依次得到排序后的数组;

第一次交换:

C语言实现堆排序_第7张图片 排序后:

 C语言实现堆排序_第8张图片

 第二次交换:

C语言实现堆排序_第9张图片

 依次执行即可实现排序操作。

具体方法实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 

void Swap(int *arr, int x, int y)
{
	int temp = 0;
	temp = arr[x];
	arr[x] = arr[y];
	arr[y] = temp;
}

void HeapInsert(int *arr, int index)
{
	while (arr[index] > arr[(index - 1) / 2])
	{
		//交换函数swap
		Swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;
	}
}

/*
arr: 目标数组
index: 目标节点
size: 数组大小监测
*/
void HeapIfy(int *arr, int index, int size)
{
	int left = index * 2 + 1;
	while (left < size)
	{
		//找较大子节点
		int largest = (left + 1 < size && arr[left + 1] > arr[left]) ? left + 1 : left;

		//比较子节点和父节点
		if (arr[largest] > arr[index])
			Swap(arr, largest, index);
		else
			break;

		//循环结构
		index = largest;
		left = index * 2 + 1;
	}
}

void HeapSort(int* arr, int size)
{
	int i = 0;
	if (arr == NULL || size < 2)
		return;

	//进二叉树:
	for (i = 1; i < size; i++)
	{
		HeapInsert(arr, i);
	}

	//排序:
	while (size > 0)
	{
		Swap(arr, 0, --size);
		HeapIfy(arr, 0, size);
	}
}

int main()
{
	int arr[] = { 2, 3, 1, 3, 4, 5, 2, 8, 4, 7, 0, 8, 9, 3, 1 };
	int size = sizeof(arr) / sizeof(arr[0]);
	HeapSort(arr, size);

	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

你可能感兴趣的:(数据结构和算法,c语言,排序算法)