C语言数据结构之堆排序的优化算法

C语言数据结构之堆排序的优化算法攻略

堆排序简介

堆排序(HeapSort)是一种树形选择排序,在排序过程中始终保持一个最大堆,每次将堆顶元素与最后一个元素交换位置,并进行一次最大堆调整操作,直到整个序列有序为止。

堆排序的时间复杂度为O(nlogn),具有不需额外存储空间的特点,因此广泛应用于内存受限的场景。

堆排序的优化算法

1. 建堆操作的优化

将序列中的元素插入到空堆中,时间复杂度为O(nlogn),可以通过优化建堆操作,将其时间复杂度降至O(n)。

建堆操作的本质是将序列中的元素依次插入到堆中,因此可以考虑一次性将序列中的所有元素插入到堆中。具体方法如下:

void buildHeap(int a[], int n) {
    int i;
    for (i = n / 2; i >= 1; i--) {
        heapify(a, i, n);
    }
}

由于完全二叉树中叶子节点占据了一半的空间,因此从第n/2个节点开始(包括第n/2个节点)是堆中所有非叶子节点。从第n/2个节点开始,从后往前依次执行heapify操作,即每次将当前节点和其子节点进行比较并进行调整。由于叶子节点不需要调整,因此可以忽略叶子节点,将操作次数降至一半。

2. 堆调整操作的优化

堆调整操作的本质是将某个节点的值减小,从而可能影响到该节点的子节点,需要依次将该节点与其子节点进行比较,对不满足堆性质的节点进行调整。由于每次调整只是将节点移动到正确的位置,因此可以考虑将堆调整操作优化为插入操作。

具体方法如下:

void heapInsert(int a[], int n, int k) {
    int cur = n;
    a[cur] = k;
    while (cur > 1 && k > a[cur / 2]) {
        a[cur] = a[cur / 2];
        cur /= 2;
    }
    a[cur] = k;
}

每次将堆的最后一个元素插入到堆中,由于插入元素的大小可能会影响到堆的调整,因此需要按照子节点的大小依次将该元素与其父节点进行比较。如果插入元素比父节点大,则将父节点移动到当前位置,并将当前位置改为父节点,继续向上比较。最后将插入元素插入到正确的位置。

示例1

#include <stdio.h>

void heapify(int a[], int i, int n) {
    int max = i, l = 2 * i, r = l + 1;
    if (l <= n && a[l] > a[max]) {
        max = l;
    }
    if (r <= n && a[r] > a[max]) {
        max = r;
    }
    if (max != i) {
        int temp = a[i];
        a[i] = a[max];
        a[max] = temp;
        heapify(a, max, n);
    }
}

void heapSort(int a[], int n) {
    int i;
    for (i = n / 2; i >= 1; i--) {
        heapify(a, i, n);
    }
    for (i = n; i > 1; i--) {
        int temp = a[1];
        a[1] = a[i];
        a[i] = temp;
        heapify(a, 1, i - 1);
    }
}

int main() {
    int a[] = {0, 5, 2, 4, 1, 3};
    int n = sizeof(a) / sizeof(int) - 1;
    heapSort(a, n);
    int i;
    for (i = 1; i <= n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}

执行结果:

1 2 3 4 5

示例2

#include <stdio.h>

void heapInsert(int a[], int n, int k) {
    int cur = n;
    a[cur] = k;
    while (cur > 1 && k > a[cur / 2]) {
        a[cur] = a[cur / 2];
        cur /= 2;
    }
    a[cur] = k;
}

int main() {
    int a[10] = {0};
    int n = 0;
    heapInsert(a, ++n, 5);
    heapInsert(a, ++n, 1);
    heapInsert(a, ++n, 4);
    heapInsert(a, ++n, 2);
    heapInsert(a, ++n, 3);
    int i;
    for (i = 1; i <= n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}

执行结果:

5 3 4 1 2

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构之堆排序的优化算法 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • F – 产生冠军(不使用拓扑排序)

    题目描述 有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。球赛的规则如下:如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之…

    算法与数据结构 2023年4月17日
    00
  • C语言数据结构树的双亲表示法实例详解

    C语言数据结构树的双亲表示法实例详解 什么是双亲表示法 在树上,每个节点都有且仅有一个父节点(根节点除外)。对于一个树结构,我们可以使用许多方法来表示这个树,其中最常见的一种方法是双亲表示法。该表示法使用一个一维数组来存储树的节点,数组的下标即为该节点的编号,数组的值则表示该节点的父节点编号。 当一个节点没有父节点时,该节点即为根节点。 双亲表示法的优缺点 …

    数据结构 2023年5月17日
    00
  • ecnuoj 5042 龟速飞行棋

    5042. 龟速飞行棋 题目链接:5042. 龟速飞行棋 赛中没过,赛后补题时由于题解有些抽象,自己写个题解。 可以发现每次转移的结果只跟后面两个点的胜负状态有关。 不妨设 \(f_{u,a,b}\) 表示,\(u+1\) 号点的胜负态为 \(a\),\(u+2\) 号点的胜负态为 \(b\),此时从 \(1\) 号点出发的胜负态是什么。那么可以发现,利用 …

    算法与数据结构 2023年4月17日
    00
  • java数据结构基础:算法

    Java数据结构基础:算法攻略 概述 在程序员的日常开发中,算法是一项重要的技能,而数据结构则是算法不可缺少的基础。本文将讲解Java数据结构中的基本算法,包括常见算法的实现,算法的分析及算法的运用。经过本文的学习,读者可以掌握Java中基础的算法实现及应用。 常见算法实现 排序算法 排序算法是算法中最基础的一类,常用的算法有冒泡排序、插入排序、选择排序、快…

    数据结构 2023年5月17日
    00
  • java实现队列queue数据结构详解

    Java实现队列(Queue)数据结构详解 什么是队列(Queue) 队列(Queue),是一种先进先出(First In First Out, FIFO)的数据结构,即最先进入队列的元素也会最先出队列。 队列具备两个基本操作:入队(enqueue)和出队(dequeue)。入队操作将元素加入到队列的尾部,出队操作将元素从队列头部取出并删除。 Java中的Q…

    数据结构 2023年5月17日
    00
  • Lua教程(七):数据结构详解

    Lua教程(七):数据结构详解 Lua 中的数据结构广泛应用于各种计算机程序中。本文将详细介绍 Lua 中的数组、列表、栈、队列、集合和字典等数据结构的使用以及相关的函数。 数组 数组是存储在连续内存位置上的相同数据类型的元素集合。Lua 中的数组索引默认从 1 开始。下面是一些常用的 Lua 数组函数: table.concat(arr[, sep[, i…

    数据结构 2023年5月17日
    00
  • C#常用数据结构和算法总结

    C#常用数据结构和算法总结 数据结构 数组(Array) 数组是一种线性数据结构,它可以在内存中连续地存储相同类型的数据。可以使用索引访问数组中的元素。数组的元素可以是任意类型。 在 C# 中,定义一个数组需要指定数组的类型和数组的大小。例如,定义一个包含 5 个整数的数组: int[] arr = new int[5]; 链表(LinkedList) 链表…

    数据结构 2023年5月17日
    00
  • C++数据结构链表基本操作示例过程

    C++数据结构链表基本操作示例过程 链表是一种重要的数据结构,C++中链表的操作是非常常见的,下面我将详细介绍C++中链表的基本操作,包括创建链表、插入节点、删除节点和遍历链表等。 创建链表 首先,需要创建一个链表结构体,并定义节点类型struct Node,其中包含元素数据及下一个节点的指针。 struct Node { int data; Node* n…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部