堆的基础操作(C语言)

目录

堆的定义

堆的基本操作

源代码

运行截图


堆的定义

n个元素称为堆,当且仅当它的关键字序列k1, k2, .... , kn,满足:

ki <= k2i , ki <= k2i+1 (小根堆or最小堆)         或者          ki >= k2i,   ki >= k2i+1(大根堆or最大堆)

其中 i的取值范围为[1, n/2]    (i , 2i, 2i+1均为下标)

将堆看成一棵完全二叉树,以大根堆为例,也就是根结点的元素值均大于左右孩子的元素值。

关于i最大值为n/2的原因是:一棵有n个结点的完全二叉树,序号大于n/2的结点均为叶子结点,故以这些结点为根的子树已经是堆。

堆的基本操作

void lift_up(int h[ ], int i)                       //把第i个元素上移

void lift_down(int h[ ], int i, int n)          //把第i个元素下移

void Insert(int h[ ], int x, int &n)            //把元素x插入堆中

void Delete(int h[ ], int &n, int i)            //删除堆中第i个元素

int Delete_Max(int h[ ], int & n)            //删除并返回最大元素(根结点)

void CreateHeap(int h[ ], int n)            //建立堆

void heap_sort(int h[ ], int A[ ], int& n) //堆排序

源代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>

//大根堆为例
//交换
void swap(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

//打印数组
void printheap(int h[], int n) {
	for (int i = 1;i <= n;i++) {
		printf("%d ", h[i]);
	}
}


void lift_up(int h[], int i) {
	//将元素i上移,保持大根堆
	bool done = false;//标记是否完成
	while (!done && i != 1) {
		if (h[i] > h[i / 2]) {
			//大于父亲结点就上移(与父亲结点交换)
			swap(h, i, i / 2);
		}
		else {
			done = true;//标志交换结束
		}
		i = i / 2;
	}
}


void lift_down(int h[], int i, int n) {
	//下移元素
	bool done = false;
	while (!done && (i = 2 * i) <= n) {
        //i*2 ,i为原来i的左孩子结点
		if ((i + 1 <= n) && h[i] < h[i + 1]) {
            //如果左孩子小于右孩子,i指向右孩子
			i++;
		}
		if (h[i / 2] < h[i]) {
            //如果孩子结点比父亲结点值大,交换
			swap(h, i / 2, i);
		}
		else {
			done = true;
		}
	}
}

//将元素插入堆
void Insert(int h[], int x, int& n) {
	n++;//堆的元素个数加一
	h[n] = x;//插入到最后一个位置
	lift_up(h, n);//再将插入的元素上移到它应该存在的位置
}

//删除元素i
void Delete(int h[], int i, int& n) {	                                                                                                                                                                                                 
	int x = h[i];//x记录待删除的元素
	if (i <= n) {
		h[i] = h[n];//用最后一个元素替代之
		n--;//堆长度减一
		if (h[i] < x) {
			//如果最后一个元素比待删除的元素小,就下移调整
			lift_down(h, i, n);
		}
		else {
            //反之,大就上移
			lift_up(h, i);
		}
	}
}

//删除最大元素(堆顶元素)
int Delete_Max(int h[], int& n) {
	int x = h[1];
	Delete(h, 1, n);//删除堆顶元素
	return x;
}

//建立堆
void CreateHeap(int h[], int n) {
	for (int i = n / 2;i >= 1;i--) {
        //从最后一片树叶,找到其上面的分支结点,从该分支结点开始做下一操作,一直到根节点。
		lift_down(h, i, n);
	}
}

//建立堆的第二种方法
void CreateHeap2(int h[], int n) {
	int m = 0;//堆的大小初始为0
	for (int i = 0;i < n;i++) {
		Insert(h, h[i + 1], m);
	}
}

//堆排序方法1
void heap_sort(int h[], int A[], int n) {
	for (int i = n;i > 1;i--) {
		swap(h, 1, i);//交换堆顶元素和堆的最后一个元素
        //对于一开始的堆,堆顶元素为最大值,交换之后堆顶元素被置换至数组尾部。
		lift_down(h, 1, i - 1);//一轮循环在i个元素中找出一个最大值,将其舍弃,调整剩下的i-1个元素再次成为大根堆,反复
	}
}

//堆排序方法2
void heap_sort2(int h[], int A[], int n, int sz) {
	//n为堆当前的大小(随着delete_max的调用n会不断减小),sz为初始时堆的元素个数
	for (int i = 1;i <= sz;i++) {
		A[sz - i + 1] = Delete_Max(h, n);
	}
}

//主函数部分
int main() {
	int test[10] = { 0 };
	int n = 10;//初始堆大小为10
	int h[11] = { 0,20,15,8,5,4,2,3,13,18,25 };//第一号位置不存元素
	CreateHeap(h, n);
    //CreateHeap2(h, n);
	printf("初建堆为:");
	printheap(h, n);
	int x = Delete_Max(h, n);
	printf("\n删除堆中最大元素:%d", x);
	printf("\n删除后堆为:");
	printheap(h, n);
	int insert = 30;
	Insert(h, insert, n);
	printf("\n插入元素insert后的堆为:");
	printheap(h, n);
	Delete(h, 5, n);
	printf("\n删除5号元素后的堆为:");
	printheap(h, n);
	int sz = n;
	heap_sort2(h, test, n, sz);
	printf("\n堆排序(递增):");
	printheap(test, n);
	system("pause");
	return 0;
}

运行截图

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值