堆的基本操作实现

一、堆的概念

        堆数据结构是一种数据对象,它可以被视为一棵完全二叉树结构。

        堆的二叉树存储是:

                最大堆:每个父节点都大于其孩子结点;

                最小堆:每个父节点都小于其孩子结点。

二、堆的实现

1.堆的结构体

typedef struct Heap { 
    HeapType data[HeapMaxSize]; 
    size_t size; 
    Compare cmp; 
} Heap; 

2.堆的初始化

        堆的初始化就是对结构体中的 size 和 cmp函数指针进行初始化,size =0,cmp有俩种选项可供选择:大堆(Greater)和小堆(Less)。

int Less(HeapType a,HeapType b){
    return a<b?1:0;
}
int Greater(HeapType a,HeapType b){
    return a>b?1:0;
}
//堆的初始化
void HeapInit(Heap* heap, Compare cmp){
    if(heap == NULL){
        //非法输入
        return;
    }
    heap->size = 0;
    heap->cmp = cmp;
    return;
}

3.打印堆与元素的交换

    堆的打印:为了清晰的对堆元素进行查看;

    元素的交换:每次对堆操作,会影响堆的排列顺序,所以应该调用交换元素的函数的方式对堆进行调整,使其满足对于堆的结构(调用元素交换函数时,应该传入 元素的地址(传置))。

//层序遍历堆
void print_Heap(Heap heap,char* msg){
    printf("\n*******%s***********\n",msg);
    int i = 0;
    for(;i<heap.size;++i){
        printf("%d ",heap.data[i]);
    }
    printf("\n");
    return;
}
//,交换函数 
void swap(int * a,int * b){
    int tmp = *a;
    *a = *b;
    *b = tmp;
    return;
}

4.堆的插入实现

对堆进行插入操作可由以下步骤实现:

i>判断堆是否为空堆

ii>堆为空,直接插入,,堆不为空,将带插入值先插至结构体数组的size处,并将size进行++操作

iii>将size-1视为cur,(cur-1)/2视为parent,并进入 while(cur>=0)循环,若cur处的值与parent处的值满足堆结构,直接退出,否则进行交换,然后使cur = parent, parent = (cur-1)/2;

iv>循环结束,变换后的堆又满足了堆的结构

//往堆里插入元素
void HeapInsert(Heap* heap, HeapType value){
    //1.判断是否为非法输入
    if(heap == NULL){
        //非法输入
        return ;
    }
    //2.判断堆是否为空
    if(heap->size == 0){
        //堆位空
        heap->data[heap->size] = value;
    }else{
        //堆不为空
        heap->data[heap->size] = value;
        int cur = heap->size;
        int parent = ( cur - 1 )/2;
        while(parent >= 0){
            if ( heap->cmp(heap->data[cur], heap->data[parent]) ){
                swap(&heap->data[cur],&heap->data[parent]);
                cur = parent;
                parent = (cur - 1)/2;
            }else{
                break;
            }
        }
    }
    ++heap->size;
    return;
}

5.取堆顶元素

//取堆顶元素
int HeapRoot(Heap* heap, HeapType* value){
    //1.判断是否为非法输入
    if(heap == NULL){
        //非法输入
        return 0;
    }
    //2.判断堆是否为空,空堆返回0,否则返回1
    if(heap->size == 0){
        //空堆 
        return 0;
    }else{
        //非空
        *value = heap->data[0];
        return 1;
    }
}

6.删除堆顶元素

        首先判断是否为空堆,如果为空堆直接返回,否则将堆首元素与堆末元素进行交换,对size进行--操作,然后调整堆的结构,使变化后的堆重新满足堆的结构。

//删除堆顶元素
void HeapErase(Heap* heap){
    //1.判断是否为非法输入
    if(heap == NULL){
        //非法输入
        return;
    }
    //2.判断堆是否为空
    if(heap->size == 0){
        //堆为空
        return;
    }else{
        //非空
        swap(&heap->data[0],&heap->data[heap->size-1]);
        --heap->size;
        int cur = 0;
        int child = 2*cur +1;
        while(child < heap->size){
            //当前结点右子树,,
            //判断该结点是否具有右子树
            if(child+1<heap->size){
                //带结点具有右子树
                //进行左右子树判断,挑选满足规定的值
                if(heap->cmp(heap->data[child],heap->data[child+1]) == 0){
                    //child不满足规定
                     ++child;
                     if(heap->cmp(heap->data[cur],heap->data[child])== 0){
                         swap(&heap->data[cur],&heap->data[child]);
                         cur = child;
                         child = ( cur-1 ) /2;
                     }else{
                         return;
                     }
                }else{
                    //child满足规定
                     if(heap->cmp(heap->data[cur],heap->data[child])== 0){
                         swap(&heap->data[cur],&heap->data[child]);
                         cur = child;
                         child = 2*cur+1;
                     }else{
                         return;
                     }
                }
            }else{
                //cur无右子树
                if(heap->cmp(heap->data[cur],heap->data[child])== 0){
                    swap(&heap->data[cur],&heap->data[child]);
                    cur = child;
                    child = ( cur-1 ) /2;
                }else{
                    return;
                }
            }
        }
    }
    return;
}

7.堆的销毁

堆的销毁,可以直接将堆结构体中的size置为0就好,此处进行了大规模的处理,是为了方便使用堆对数组进行排序。

//堆的销毁
void HeapDestroy(Heap* heap){
    //1.判断是否为非法输入
    if(heap == NULL){
        //非法输入
        return;
    }
    //2.判断是否为空堆
    if(heap->size == 0){
        //为空
        return;
    }else{
        //非空
        while(heap->size){
            HeapErase(heap);
        }
        return;
    }
}

8.堆排序

堆排序实质上是为了解决数组的排序,如果要将数组进行升序排列,就采用大堆实现,如果要将数组进行降序排列,就采用小堆实现。

//堆排序函数
void HeapSort(HeapType array[], size_t size){
    int i = 0;
    Heap heap ;
    HeapInit(&heap,Greater);
    for(;i<size;i++){
        HeapInsert(&heap,array[i]);
    }
    HeapDestroy(&heap);
    Heap new_heap = heap;
    new_heap.size = size;
    print_Heap(new_heap,"HeapSord");
    return;
}

9.以上函数的检测代码

//堆排序的检测函数
void textHeapSort(){
    int array[] = {1,2,3,4};
    HeapSort(array,sizeof(array)/sizeof(array[0]));
    return;
    
}
//堆销毁的检测函数
void textHeapDestroy(){
    Heap heap ;
    HeapInit(&heap,Greater);
    HeapInsert(&heap,1);
    HeapInsert(&heap,2);
    HeapInsert(&heap,3);
    HeapInsert(&heap,4);
    int size = heap.size;
    HeapDestroy(&heap);
    print_Heap(heap,"堆删除");
    return;
}
//删除堆顶元素的检测函数
void textHeapErase(){
    Heap heap ;
    HeapInit(&heap,Greater);
    HeapInsert(&heap,1);
    HeapInsert(&heap,2);
    HeapInsert(&heap,3);
    HeapInsert(&heap,4);
    HeapErase(&heap);
    print_Heap(heap,"删除堆顶元素");
    return;
}
//取堆顶元素的检测函数
void textHeapRoot(){
    Heap heap ;
    HeapInit(&heap,Greater);
    HeapInsert(&heap,1);
    HeapInsert(&heap,2);
    HeapInsert(&heap,3);
    HeapInsert(&heap,4);
    HeapType value;
    int ret = HeapRoot(&heap,&value);
    printf("\n*******取堆顶元素***********\n");
    printf("ret except:1  actual:%d\n",ret);
    printf("value except:4   actual:%d\n",value);
}
//堆插入的检测函数
void textHeapInsert(){
    Heap heap ;
    HeapInit(&heap,Greater);
    HeapInsert(&heap,1);
    HeapInsert(&heap,2);
    HeapInsert(&heap,3);
    HeapInsert(&heap,4);
    print_Heap(heap,"堆插入四个元素");
    return;
}
//堆初始化的检测函数 
void textHeapInit(){
    Heap heap ;
    HeapInit(&heap ,Greater);
    print_Heap(heap,"对堆进行初始化");
    return;
}

10.主函数

//主函数
int main(){
    textHeapInit();//堆初始化的检测函数
    textHeapInsert();//堆插入一个元素
    textHeapRoot();//取堆顶元素的检测函数
    textHeapErase();//删除堆顶元素的检测函数
    textHeapDestroy();//堆删除的检测函数
    textHeapSort();//
    return 0;
}
11.检测结果
*******对堆进行初始化***********


*******堆插入四个元素***********
4 3 2 1 

*******取堆顶元素***********
ret except:1  actual:1
value except:4   actual:4

*******删除堆顶元素***********
3 1 2 

*******堆删除***********


*******HeapSord***********
1 2 3 4 

阅读更多
个人分类: 数据结构
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭