好看的网站页面设计百度竞价点击一次多少钱
二叉树(堆)
简介
前文,我们大概的介绍了一下树的一些基本概念,然后这节就主要讲解一下二叉树的其中一种存储方式:用数组存储(顺序存储)。及其一些特殊结构,也就是堆。
注意一下就是,这种用数组存储二叉树的方式只适用于完全二叉树。非完全二叉树的话就更加适合链式存储,这个后面讲。
堆
堆是什么呢?
堆的插入
讲完基本的思路,那么就要开始写代码了。
堆的实现及其功能代码
头文件.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>//数据类型
typedef int HPDataType;typedef struct Heap
{HPDataType *a;//数组首元素地址int size;//数组中有效元素的个数(数组大小)int capacity;//数组的容量
}HP;//向上调整
void AdjustUp(HPDataType* a,int child);
//向下调整
void AdjustDown(HPDataType* a,int n,int parent);//交换函数
void Swap(HPDataType* p1,HPDataType* p2);//打印函数
void HeapPrint(HP* pq);
//初始化函数
void HeapInit(HP* pq);
//第二种初始化函数
void HeapInitArray(HP* pq,int* a,int n);
//摧毁函数
void HeapDestroy(HP* pq);//插入函数
void HeapPush(HP* pq,HPDataType x);
//删除函数
void HeapPop(HP* pq);//获取堆顶元素
HPDataType HeapTop(HP* pq);
//判断堆是否为空
bool HeapEmpty(HP* pq);
实现文件.c
#include "Heap.h"//初始化函数
void HeapInit(HP* pq)
{assert(pq);pq->a=NULL;pq->size=pq->capacity=0;
}
//第二种初始化函数(把已经存在的数组,复制一份给我们的数组)
void HeapInitArray(HP* pq,int* a,int n)
{assert(pq);assert(a);//这里直接开了一个大小为n的数组空间pq->a=(HPDataType*) malloc(sizeof (HPDataType)*n);if(pq->a==NULL){perror("malloc failed");exit(-1);}pq->capacity=n;memcpy(pq->a,a,sizeof (HPDataType)*n);pq->size=n;//建堆for(int i=1;i<n;i++){AdjustUp(pq->a,i);}
}//摧毁函数
void HeapDestroy(HP* pq)
{assert(pq);free(pq->a);pq->a=NULL;pq->size=pq->capacity=0;
}//交换函数
void Swap(HPDataType* p1,HPDataType* p2)
{HPDataType tmp=*p1;*p1=*p2;*p2=tmp;
}//向上调整(建小堆)
void AdjustUp(HPDataType* a,int child)
{int parent=(child-1)/2;while(child>0){if(a[child]<a[parent]){Swap(&a[child],&a[parent]);child=parent;parent=(child-1)/2;//parent=(parent-1)/2;}else{break;}}}
//向下调整(小堆)
void AdjustDown(HPDataType* a,int n,int parent)
{int child=parent*2+1;while(child<n){//找到大的那个孩子if(child+1<n&&a[child+1]<a[child]){child++;}if(a[child]<a[parent]){Swap(&a[child],&a[parent]);//继续向下调整parent=child;child=parent*2+1;}else{break;}}
}//插入函数
void HeapPush(HP* pq,HPDataType x)
{assert(pq);//判断容量是否足够if(pq->size==pq->capacity){int newCapacity=pq->capacity==0?4:pq->capacity*2;HPDataType* tmp=(HPDataType*) realloc(pq->a,sizeof (HPDataType)*newCapacity);if(tmp==NULL){perror("reallocate failed");exit(-1);}pq->a=tmp;pq->capacity=newCapacity;}pq->a[pq->size]=x;pq->size++;AdjustUp(pq->a,pq->size-1);
}
//删除函数
void HeapPop(HP* pq)
{assert(pq);assert(pq->size>0);Swap(&pq->a[0],&pq->a[pq->size-1]);pq->size--;AdjustDown(pq->a,pq->size,0);
}//获取堆顶元素
HPDataType HeapTop(HP* pq)
{assert(pq);assert(pq->size>0);return pq->a[0];
}
//判断堆是否为空
bool HeapEmpty(HP* pq)
{assert(pq);return pq->size==0;
}//打印函数
void HeapPrint(HP* pq)
{assert(pq);for(int i=0;i<pq->size;i++){printf("%d ",pq->a[i]);}printf("\n");
}
测试文件.c
#include "Heap.h"/*
void HeapSort(int* a,int n)
{for(int i=(n-1-1)/2;i>=0;i--){AdjustDown(a,n,i);}int end=n-1;while(end>0){Swap(&a[0],&a[end]);AdjustDown(a,end,0);end--;}
}int main()
{int a[]={65,100,70,32,50,60};HeapSort(a,sizeof (a)/sizeof (int));return 0;
}*/
void PrintTopK(const char* filename, int k)
{// 1. 建堆--用a中前k个元素建堆FILE* fout = fopen(filename, "r");if (fout == NULL){perror("fopen fail");return;}int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("malloc fail");return;}for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);}// 前k个数建小堆for (int i = (k-2)/2; i >=0 ; --i){AdjustDown(minheap, k, i);}// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换int x = 0;while (fscanf(fout, "%d", &x) != EOF){if (x > minheap[0]){// 替换你进堆minheap[0] = x;AdjustDown(minheap, k, 0);}}for (int i = 0; i < k; i++){printf("%d ", minheap[i]);}printf("\n");free(minheap);fclose(fout);
}// fprintf fscanfvoid CreateNDate()
{// 造数据int n = 1000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < n; ++i){int x = (rand() + i) % 10000000;fprintf(fin, "%d\n", x);}fclose(fin);
}int main()
{//CreateNDate();//要先使用这个函数创建一个含有N个数据的文本文件,然后注释掉,使用下面那个函数PrintTopK("data.txt", 5);return 0;
}
解析
-
结构
-
初始化函数和销毁函数
-
插入函数
- 向上调整函数
结合下图理解代码
- 删除函数
- 向下调整函数
建堆
建堆什么意思呢?顾名思义,就是建立起一个堆,可以是大堆,可以是小堆,这里我们以建立小堆给大家讲解。然后我们顺便用上删除操作,这样就可以得到一个简单的排序的手法。
优化