本代码适用于
堆初始化在本例已经内置,无需添加。
icoding的数据结构并没有一个测试代码,其都是直接编写一个函数的形式,因此很难知道自己的实际输出是什么。针对部分题目,我编写了一系列测试代码以供大家进行数据输出的测试。
//堆辅助函数 int parent(int i) //返回堆元素数组下标为 i 的结点的父结点下标 { //TODO } int left(int i) //返回堆元素数组下标为 i 的结点的左子结点下标 { //TODO } int right(int i) //返回堆元素数组下标为 i 的结点的右子结点下标 { //TODO } void swap_node(MinHeapNode *x, MinHeapNode *y) //交换两个堆元素的值 { //TODO } //堆插入 bool heap_insert_value(PMinHeap pq, int value) { //TODO } //堆化 void min_heapify(PMinHeap pq, int i){ //todo }
请将您的函数代码复制到上述函数中,然后修改main函数的相关内容,完成测试样例的输入
因为技术受限,只能以列表形式输出结果,暂不能以树状形式输出,请谅解~
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
typedef struct _otherInfo
{
int i;
int j;
}OtherInfo;
typedef struct _minHeapNode
{
int value;
OtherInfo otherInfo;
}MinHeapNode, *PMinHeapNode;
typedef struct _minPQ {
PMinHeapNode heap_array; // 指向堆元素数组
int heap_size; // 当前堆中的元素个数
int capacity; //堆数组的大小
}MinHeap, *PMinHeap;
//初始化最小堆
void init_min_heap(PMinHeap pq, int capacity){
pq->capacity=capacity;
pq->heap_size=0;
pq->heap_array=(PMinHeapNode)malloc(capacity*sizeof(MinHeapNode));
}
//打印堆
void print_min_heap(PMinHeap pq){
printf("heap_size:%d\t",pq->heap_size);
printf("capacity:%d\n",pq->capacity);
printf("序号|\tval\ti\tj\n");
printf("--------------------------------\n");
for(int i=0;i<pq->heap_size;i++){
if(i<10)
printf("[%d] |\t%d\t%d\t%d\n",i,pq->heap_array[i].value,pq->heap_array[i].otherInfo.i,pq->heap_array[i].otherInfo.j);
else
printf("[%d]|\t%d\t%d\t%d\n",i,pq->heap_array[i].value,pq->heap_array[i].otherInfo.i,pq->heap_array[i].otherInfo.j);
}
printf("\n");
}
//从数组中堆元素插入
bool heap_insert_value_fromarr(PMinHeap pq, int val[],int other_i[],int other_j[]){
if(pq->heap_size==pq->capacity){
printf("堆已满!程序自动终止,请增大capacity的值\n");
return false;
}
pq->heap_size++;
int i=pq->heap_size-1;
pq->heap_array[i].value=val[i];
pq->heap_array[i].otherInfo.i=other_i[i];
pq->heap_array[i].otherInfo.j=other_j[i];
while(i!=0&&pq->heap_array[i].value<pq->heap_array[(i-1)/2].value){
MinHeapNode temp=pq->heap_array[i];
pq->heap_array[i]=pq->heap_array[(i-1)/2];
pq->heap_array[(i-1)/2]=temp;
i=(i-1)/2;
}
return true;
}
//无序堆的插入
bool heap_insert_nosort_fromarr(PMinHeap pq, int val[],int other_i[],int other_j[]){
if(pq->heap_size==pq->capacity){
printf("堆已满!程序自动终止,请增大capacity的值\n");
return false;
}
pq->heap_size++;
int i=pq->heap_size-1;
pq->heap_array[i].value=val[i];
pq->heap_array[i].otherInfo.i=other_i[i];
pq->heap_array[i].otherInfo.j=other_j[i];
while(i!=0&&i!=1&&i!=2&&pq->heap_array[i].value<pq->heap_array[(i-1)/2].value){
MinHeapNode temp=pq->heap_array[i];
pq->heap_array[i]=pq->heap_array[(i-1)/2];
pq->heap_array[(i-1)/2]=temp;
i=(i-1)/2;
}
return true;
}
//查找标号为i的元素
PMinHeapNode heap_find_node(PMinHeap pq,int i){
if(i>=pq->heap_size){
//printf("未找到元素%d!\n",i);
return NULL;
}
return &pq->heap_array[i];
}
//------------------以上为辅助函数------------------
int parent(int i){
//TODO
}
int left(int i){
//TODO
}
int right(int i){
//TODO
}
void swap_node(MinHeapNode *x, MinHeapNode *y){
//TODO
}
bool heap_insert_value(PMinHeap pq, int value){
//TODO
}
void min_heapify(PMinHeap pq, int i){
//TODO
}
int main(){
//-------------以 下 内 容 可 以 修 改------------------
int val[]={607, 136, 333, 170,54, 275, 527, 743, 506, 927, 572, 952};
int other_i[]={1,2,3,4,5,6,7,8,9,10,11,12};
//以上分别代表堆的值,和其对应的i,j(见结构体的OtherInfo)
//为了方便大家,我们把i,j的值都设置成了i的值;即 other_j[]的值与other_i[]的值相同,您只需定义other_i[]即可
//icoding会检查i,j的值是否匹配,所以对于辅助函数题目的swap函数不要只交换value哦
//必须保证数组的长度小于堆的容量
//保证三个数组的值相等
//【重要】您无需在意数组的顺序是否满足递增/递减,对于辅助函数、堆插入这两个题目我们会自动为排序,初始化的堆一定是最小堆;
//对于堆化题目,题目意思是,根节点左右两棵子树均满足最小堆要求,但整颗树因为有根节点所以不满足,需要调整根节点。
//本程序在运行堆化题目时,默认第一个节点(根节点)不动,但自动排列生成根节点左右子树均满足最小堆的堆。您也无需在意数组的单调性。
//总而言之,您可以随意输入数据,我们会自动按照题目相关要求生成对应的正确最小堆。
//对于第三题,我们也提供了一些已经成型的除了根节点外均满足最小堆(即根节点的左右子树都满足最小堆)的数组排列
//第三题的val测试数据
// (1) 7, 130, 128, 171, 204, 377, 569, 259, 290, 358, 629, 799, 518, 747, 576, 984, 742, 871, 432, 586, 499, 748, 926
// 数据长度为23
// (2) 7, 130, 128, 171, 204, 377, 569, 259
// 数据长度为8
// (3) 2 28, 34, 131, 228, 129, 838, 374, 858, 266, 645, 531
// 数据长度为12
// (4) 363, 158, 239, 372, 280, 508, 693
// 数据长度为7
// (5) 607, 136, 54, 333, 170, 275, 527, 743, 506, 927, 572, 952
// 数据长度为12
int capacity=50;//堆的容量,建议比val大一点,以顺利完成插入。
//您也可以修改capacity以检查当容量超出时相关函数的返回是否正常,但icoding不测试这一点。
bool assist_flag=true;//辅助函数题目是否测试,true为测试,false为不测试
int test_num=2;//辅助函数,parent/left/right函数传入值
int swap_test_1=1;//辅助函数,swap_node函数要交换的节点的序号(数组下标)
int swap_test_2=2;//辅助函数,swap_node函数要交换的节点的序号(数组下标)
//swap_test_1和swap_test_2的值不能相同
bool insert_falg=true;//heap_insert_value函数是否测试,true为测试,false为不测试
int insert_test_num=50;//heap_insert_value函数要插入的值,擦入的ij值默认是0
bool min_heapify_flag=true;//min_heapify函数是否测试,true为测试,false为不测试
//第三题传入的int数据 min_heapify_test_num 默认为0,暂时不支持调整。
//他的意思是:根节点(0号节点)这个节点不满足最小堆的要求,需要调整。但根节点的左右子树各自满足最小堆的要求。
对于堆化题目,题目意思是,根节点左右两棵子树均满足最小堆要求,但整颗树因为有根节点所以不满足,需要调整根节点。
//icoding测试样例传入的int的数据也是均为0
//-------------以 上 内 容 可 以 修 改------------------
printf("icoding\n排序-堆\n----开始测试----\n");
int len_i=sizeof(other_i)/sizeof(int);
int other_j[len_i];
//初始化other_j
for(int i=0;i<len_i;i++)
other_j[i]=other_i[i];
int len_j=sizeof(other_j)/sizeof(int);
int len=sizeof(val)/sizeof(int);
//检测三个数组的长度是否相等
if(len!=len_i||len!=len_j||len_i!=len_j){
printf("val/other_i/other_j数组长度不相等!程序自动终止,请修改\n其中,val共计%d个元素,other_i共计%d个元素,other_j共计%d个元素\n",len,len_i,len_j);
return 0;
}
//检测堆是否超出容量
if(len>capacity){
printf("堆容量不足!初始化的数据已经大于堆的容量了!程序自动终止,请修改capacity\n您输入的数据容量为%d,堆的容量为%d.建议容量比数据至少多1(即%d),以方便添加元素\n",len,capacity,len+1);
return 0;
}
printf(">>正在初始化堆(堆初始化函数无需完成,本例已内含初始化代码)\n");
PMinHeap pq=(PMinHeap)malloc(sizeof(MinHeap));
init_min_heap(pq,capacity);
printf("##提示:\n对于辅助函数、堆插入的题目,我们已经自动建立了有序的堆;\n对于堆化,我们是根据数组的顺序依次初始化无序堆,需要自己调用你编写的堆化函数使其变成有序堆\n");
//printf("\n>>正在插入初始化数据\n");
for(int i=0;i<len;i++){
heap_insert_value_fromarr(pq,&val[0],&other_i[0],&other_j[0]);
}
printf("-------------\n");
if(assist_flag){
//检查parent/left/right函数是否正确
int test=rand()%9+1;
if(parent(test)!=(test-1)/2||left(test)!=2*test+1||right(test)!=2*test+2){
printf("\n\n!!!您的parent/left/right 函数错误,请您修改!!!\n但程序仍然执行相关函数\n\n");
}
}
if(assist_flag){
printf(">>打印初始化堆\n");
print_min_heap(pq);
printf(">>辅助函数,test_num为%d\n",test_num);
printf("parent返回:%d\t 正确结果:%d\t%s\n",parent(test_num),(test_num-1)/2,parent(test_num)==(test_num-1)/2?"true":"false");
printf("left返回 :%d\t 正确结果:%d\t%s\n",left(test_num),2*(test_num)+1,left(test_num)==2*(test_num)+1?"true":"false");
printf("right返回 :%d\t 正确结果:%d\t%s\n",right(test_num),2*(test_num)+2,right(test_num)==2*(test_num)+2?"true":"false");
PMinHeapNode swap_test_node1=heap_find_node(pq,swap_test_1);
PMinHeapNode swap_test_node2=heap_find_node(pq,swap_test_2);
if(swap_test_node1==NULL||swap_test_node2==NULL){
printf("swap_test_1/2在堆中找不到,请修改!本次跳过swap_node函数的测试\n");
}
else if(swap_test_1==swap_test_2){
printf("swap_test_1/2为相同的元素,请修改!本次跳过swap_node函数的测试\n");
}
else{
swap_node(swap_test_node1,swap_test_node2);//两个参数为指针
printf("swap_node :\n已经交换标号[%d]与[%d]的节点\n\n",swap_test_1,swap_test_2);
print_min_heap(pq);
printf("请检查val && i && j的值是否正确交换\n将重新初始化堆。本次交换仅为临时存储。后续测试基于最初的堆\n");
//重新初始化
init_min_heap(pq,capacity);
for(int i=0;i<len;i++){
heap_insert_value_fromarr(pq,&val[0],&other_i[0],&other_j[0]);
}
printf("堆已经重新初始化\n");
}
}else{
printf("辅助函数跳过测试,若需要请修改assist_flag\n后续题目中若需要用到辅助函数,请务必保证完成正确的编写。否则可能导致出错\n");
}
printf("------------\n");
if(insert_falg){
printf(">>打印初始化堆\n");
print_min_heap(pq);
printf(">>正在插入元素%d\n",insert_test_num);
//检查容量是否足够插入
if(len==capacity){
printf("堆容量可能不足!\n测试的数据容量为%d,堆的容量为%d,现在还额外需要一个容量以插入(即%d)\n插入可能无法正常进行,但函数仍然会运行\n",len,capacity,len+1);
}
heap_insert_value(pq,insert_test_num);
printf(">>插入完成\n");
print_min_heap(pq);
}else{
printf("insert_test_num跳过测试,若需要请修改insert_falg\n");
}
printf("------------\n");
if(min_heapify_flag){
//检查parent/left/right函数是否正确
int test=rand()%10;
if(parent(test)!=(test-1)/2||left(test)!=2*test+1||right(test)!=2*test+2){
printf("\n\n!!!您的parent/left/right 函数错误,请您修改!!!\n但程序仍然执行相关函数\n\n");
}
}
if(min_heapify_flag){
init_min_heap(pq,capacity);
printf(">>正在初始化非根节点数据(根节点的左右两子树均为有序最小堆,但含根节点的整棵树可能无序)\n##本题题意是,根节点左右两棵子树均满足最小堆要求,但整颗树因为有根节点所以不满足\n您需要调整根节点,使得整颗树满足最小堆要求。\n");
for(int i=0;i<len;i++){
heap_insert_nosort_fromarr(pq,&val[0],&other_i[0],&other_j[0]);
}
printf(">>打印初始化堆(根节点的左右两子树均为有序最小堆,但含根节点的整棵树可能无序)\n");
print_min_heap(pq);
int min_heapify_test_num=0;//min_heapify函数要调整的节点的序号,默认都是0,不建议改
printf(">>正在调整堆\n");
min_heapify(pq,min_heapify_test_num);
printf(">>调整完成\n");
print_min_heap(pq);
}else{
printf("min_heapify_flag跳过测试,若需要请修改min_heapify_flag\n");
}
printf("\n\n----测试结束----\n");
return 0;
}
若有任何操作的疑问可以看文章 如何使用测试代码