堆排序算法

堆排序

1. 申明

C 实现:

c 复制代码
typedef struct {
	int* data;				// 数据域
	int capacity;			// 最大容量
	int len;				// 约束堆的数据长度
}MinHeap;

Java 实现:

java 复制代码
public class MinHeap<T extends Comparable<T>> {

    private T[] data;               // 数据域
    private int capacity;           // 容量
    private int len;                // 数据域

}

2. 创建

C 实现:

c 复制代码
MinHeap* createMinHeap(int n) {
	MinHeap* heap = malloc(sizeof(MinHeap));
	if (heap == NULL) return NULL;
	heap->data = malloc(sizeof(int) * (n + 1));
	if (heap->data == NULL) {
		free(heap->data);
		return NULL;
	}
	heap->len = 0;
	heap->capacity = n;
	memset(heap->data, 0, sizeof(int) * (n + 1));
	return heap;
}

Java 实现:

java 复制代码
    @SuppressWarnings("unchecked")
    public MinHeap(int capacity) {
        this.capacity = capacity;
        this.len = 0;
        this.data = (T[])new Comparable[capacity + 1];
    }

3. 插入

  1. 在最后一个位置,插入新元素
  2. 上浮,找到这个新元素的父节点,如果父节点大,那么就交换父子
  3. 继续将交换的父节点值当作待确定值,再和它的父节点比较
  4. 不断循环,直到达到根节点或者满足堆的性质

C 实现:

c 复制代码
static void siftUp(MinHeap* heap, int k) {
	while (k > 1 && heap->data[k] < heap->data[k / 2]) {
		int tmp = heap->data[k];
		heap->data[k] = heap->data[k / 2];
		heap->data[k / 2] = tmp;
		k /= 2;
	}
}

void insertMinHeap(MinHeap* heap, int e) {
	if (heap->len >= heap->capacity) {
		printf("Heap Full\n");
	}
	// 在末端插入元素
	heap->data[++heap->len] = e;
	siftUp(heap, heap->len);
}

Java 实现:

java 复制代码
    public void insertMiniHeap(T e) {
        if (this.len >= this.capacity) {
            throw new IllegalStateException("Heap is full");
        }
        this.data[++this.len] = e;
        siftUp(this.len);
    }

    private void siftUp(int index) {
        while (index > 1 && this.data[index].compareTo(this.data[index / 2]) > 0) {
            T tmp = this.data[index];
            this.data[index] = this.data[index / 2];
            this.data[index / 2] = tmp;
            index /= 2;
        }
    }

4. 提取

  1. 完全二叉树,删除一个元素,只能删除最后一个元素
  2. 删除堆顶,取出堆顶的元素值,用最后一个元素来替代根
  3. 下沉,如果有右孩子,比较左孩子和右孩子谁最小
  4. 最小的进行交换

C 实现:

c 复制代码
static void siftDown(MinHeap* heap, int k) {
	while (2 * k <= heap->len) {
		int index = 2 * k;
		if (2 * k + 1 <= heap->len && heap->data[index + 1] < heap->data[index]) {
			index = 2 * k + 1;
		}
		if (heap->data[index] > heap->data[k]) {
			break;
		}
		int tmp = heap->data[index];
		heap->data[index] = heap->data[k];
		heap->data[k] = tmp;
		k = index;
	}
}

int extractMinHeap(MinHeap* heap) {
	int ret = heap->data[1];
	heap->data[1] = heap->data[heap->len--];
	siftDown(heap, 1);
	return ret;
}

Java 实现:

java 复制代码
    public T extractMinHeap() {
        T ret = this.data[1];
        this.data[1] = this.data[this.len--];
        siftDown(1);
        return ret;
    }

    private void siftDown(int index) {
        while (2 * index < this.len) {
            int swapIndex = 2 * index;
            if (swapIndex + 1 <= this.len && this.data[swapIndex].compareTo(this.data[swapIndex + 1]) > 0) {
                swapIndex++;
            }
            if (this.data[swapIndex].compareTo(this.data[index]) > 0) {
                break;
            }
            T tmp = this.data[index];
            this.data[index] = this.data[swapIndex];
            this.data[swapIndex] = tmp;
            index = swapIndex;
        }
    }

5. 释放

C 实现:

c 复制代码
void releaseMinHeap(MinHeap* heap) {
	if (heap == NULL) return;
	if (heap->data) {
		free(heap->data);
		heap->data = NULL;
	}
	free(heap);
}

6. 完整实现

C 实现:

minHeap.h

c 复制代码
#pragma once

// 小顶堆结构,采用完全二叉树存储,从第1个位置开始存储,满足[i/2, i, 2i, 2i+1]

typedef struct {
	int* data;		// 用顺序存储方式来保存堆数据
	int len;		// 约束堆的数据长度
	int capacity;	// 最大容量
}MinHeap;

MinHeap* createMinHeap(int n);

// 动态插入数据,满足小顶堆性质
void insertMinHeap(MinHeap* heap, int e);

// 提取元素,从根上提取,保证每次提取时丢失最值
int extractMinHeap(MinHeap* heap);

void releaseMinHeap(MinHeap* heap);

minHeap.c

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "minHeap.h"

MinHeap* createMinHeap(int n) {
	MinHeap* heap = malloc(sizeof(MinHeap));
	if (heap == NULL) return NULL;
	// 从1号索引开始存放数据
	heap->data = malloc(sizeof(int) * (n + 1));
	if (heap->data == NULL) {
		free(heap);
		return NULL;
	}
	memset(heap->data, 0, sizeof(int) * (n + 1));
	heap->len = 0;
	heap->capacity = n;
	return heap;
}

void releaseMinHeap(MinHeap* heap) {
	if (heap == NULL) return;
	if (heap->data) {
		free(heap->data);
		heap->data = NULL;
	}
	free(heap);
}

// 从k索引位置处开始判断,进行上浮操作
static void siftUp(MinHeap* heap, int k) {
	// k/2表示父节点,如果父节点大,那么和父节点交换
	while (k > 1 && heap->data[k / 2] > heap->data[k]) {
		int tmp = heap->data[k];
		heap->data[k] = heap->data[k / 2];
		heap->data[k / 2] = tmp;
		k /= 2;
 	}
}

void insertMinHeap(MinHeap* heap, int e) {
	// 1. 在二叉堆中最后位置插入元素
	if (heap->len + 1 > heap->capacity) {
		printf("MinHeap Space Small\n");
		return;
	}
	heap->data[++heap->len] = e;
	// 2. 根据小顶堆性质进行上移
	siftUp(heap, heap->len);
}

static void siftDown(MinHeap* heap, int k) {
	// 有左孩子
	while (2 * k <= heap->len) {
		int index = 2 * k;
		// 存在右孩子,并且右孩子小于左孩子
		if (index + 1 <= heap->len && heap->data[index + 1] < heap->data[index]) {
			index += 1;
		}
		if (heap->data[k] <= heap->data[index]) {
			break;
		}
		int tmp = heap->data[index];
		heap->data[index] = heap->data[k];
		heap->data[k] = tmp;
		k = index;
	}
}

// 提取一定是从根节点开始,用补位的方式,进行下沉
int extractMinHeap(MinHeap* heap) {
	if (heap->len <= 0) {
		return 0;
	}
	int ret = heap->data[1];
	heap->data[1] = heap->data[heap->len--];
	siftDown(heap, 1);

	return ret;
}

main.c

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "minHeap.h"

void test01() {
	int data[] = { 9, 3, 7, 6, 5, 1, 10, 2 };
	int n = 20;
	MinHeap* minHeap = createMinHeap(n);
	for (int i = 0; i < sizeof(data) / sizeof(data[0]); i++) {
		insertMinHeap(minHeap, data[i]);
	}
	printf("array: ");
	for (int i = 1; i <= minHeap->len; i++) {
		printf("%d\t", minHeap->data[i]);
	}
	printf("\n");
	printf("extra: ");
	for (int i = 0; i < sizeof(data) / sizeof(data[0]); i++) {
		printf("%d\t", extractMinHeap(minHeap));
	}
	printf("\n");
	releaseMinHeap(minHeap);
}

test02() {
	int n = 10;
	MinHeap* heap = createMinHeap(n);
	for (int i = 0; i < n; i++) {
		int e = rand() % 100 + 1;
		insertMinHeap(heap, e);
		printf("%d\t", e);
	}
	printf("\n");
	for (int i = 0; i < n; i++) {
		printf("%d\t", extractMinHeap(heap));
	}
	printf("\n");
}

int main() {
	srand((unsigned int)time(NULL));
	test01();
	test02();
}

Java 实现:

MiniHeap

java 复制代码
package com.sonnet.heap;

public class MinHeap<T extends Comparable<T>> {

    private final T[] data;               // 数据域

    private final int capacity;           // 容量

    private int len;                // 数据域

    @SuppressWarnings("unchecked")
    public MinHeap(int capacity) {
        this.capacity = capacity;
        this.len = 0;
        this.data = (T[])new Comparable[capacity + 1];
    }

    public void insertMiniHeap(T e) {
        if (this.len >= this.capacity) {
            throw new IllegalStateException("Heap is full");
        }
        this.data[++this.len] = e;
        siftUp(this.len);
    }

    private void siftUp(int index) {
        while (index > 1 && this.data[index].compareTo(this.data[index / 2]) < 0) {
            T tmp = this.data[index];
            this.data[index] = this.data[index / 2];
            this.data[index / 2] = tmp;
            index /= 2;
        }
    }

    public T extractMinHeap() {
        T ret = this.data[1];
        this.data[1] = this.data[this.len--];
        siftDown(1);
        return ret;
    }

    private void siftDown(int index) {
        while (2 * index < this.len) {
            int swapIndex = 2 * index;
            if (swapIndex + 1 <= this.len && this.data[swapIndex].compareTo(this.data[swapIndex + 1]) > 0) {
                swapIndex++;
            }
            if (this.data[swapIndex].compareTo(this.data[index]) > 0) {
                break;
            }
            T tmp = this.data[index];
            this.data[index] = this.data[swapIndex];
            this.data[swapIndex] = tmp;
            index = swapIndex;
        }
    }
}

Test

java 复制代码
package com.sonnet.heap;

import java.util.Random;

public class Test {

    public static void main(String[] args) {
        int n = 10;
        Random random = new Random();
        MinHeap<Integer> table = new MinHeap<>(n);
        for (int i = 0; i < n; i++) {
            int e = random.nextInt(1, 100);
            System.out.print(e + "\t");
            table.insertMiniHeap(e);
        }
        System.out.println();
        for (int i = 0; i < n; i++) {
            System.out.print(table.extractMinHeap() + "\t");
        }
        System.out.println();
    }
}
相关推荐
csdn_zhangchunfeng2 小时前
Qt之智能指针使用建议
开发语言·qt
我是咸鱼不闲呀2 小时前
力扣Hot100系列24(Java)——[回溯]总结(下)(括号生成,单词搜索,分割回文串)
java·算法·leetcode
升鲜宝供应链及收银系统源代码服务2 小时前
生鲜配送供应链管理系统源代码之升鲜宝社区团购商城小程序(一)
java·前端·数据库·小程序·notepad++·供应链系统源代码·多门店收银系统
2401_895521342 小时前
Golang 构建学习
开发语言·学习·golang
tankeven2 小时前
HJ150 全排列
c++·算法
Q741_1472 小时前
每日一题 力扣 2946. 循环移位后的矩阵相似检查 力扣 155. 最小栈 数学 数组 模拟 C++ 题解
c++·算法·leetcode·矩阵·模拟·数组·
墨香幽梦客2 小时前
大数据环境下的BI架构:Hadoop与Spark的企业级应用整理
java·开发语言
熊猫_豆豆2 小时前
Python月球、地球、太阳三天体联动一个月的月相图
python·农历·月亮
handsomethefirst2 小时前
【算法与数据结构】【面试经典150题】【题41-题45】
数据结构·算法·leetcode