C++面试:堆排序、归并排序、二分查找等高阶算法

目录

堆排序 (Heap Sort)

步骤:

时间复杂度:

空间复杂度:

归并排序 (Merge Sort)

步骤:

时间复杂度:

空间复杂度:

二分查找 (Binary Search)

步骤:

时间复杂度:

空间复杂度:

面试中的应用


堆排序 (Heap Sort)

堆排序是一种基于比较的排序技术,利用二叉堆的性质来进行排序。二叉堆可以是最大堆或最小堆,在最大堆中,每个父节点的值都大于或等于其子节点的值,在最小堆中则相反。

步骤:
  1. 构建堆:将输入的无序数组构建成最大堆或最小堆。
  2. 排序
    • 在最大堆中,堆顶元素(最大值)与数组最后一个元素交换,然后减小堆的大小,并对新堆进行调整,使其满足最大堆的性质。
    • 重复此过程,直到堆的大小为 1。
时间复杂度:
  • 构建堆:O(n)
  • 调整堆:O(log n)(每次排序)
  • 总体:O(n log n)
空间复杂度:
  • O(1)(原地排序)

        堆排序使用二叉堆来排序一个数组。以下是一个最大堆排序的示例:

#include 
#include 

void heapify(std::vector &arr, int n, int i) {
    int largest = i; // 初始化最大为根
    int left = 2 * i + 1; // 左 = 2*i + 1
    int right = 2 * i + 2; // 右 = 2*i + 2

    // 如果左子节点大于根
    if (left < n && arr[left] > arr[largest])
        largest = left;

    // 如果右子节点大于最大至此
    if (right < n && arr[right] > arr[largest])
        largest = right;

    // 如果最大不是根
    if (largest != i) {
        std::swap(arr[i], arr[largest]);

        // 递归地定义子堆
        heapify(arr, n, largest);
    }
}

// 主要的堆排序函数
void heapSort(std::vector &arr) {
    int n = arr.size();

    // 构建堆(重新排列数组)
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // 一个个从堆顶取出元素
    for (int i = n - 1; i > 0; i--) {
        // 移动当前根到结尾
        std::swap(arr[0], arr[i]);

        // 调用 max heapify 在减小的堆上
        heapify(arr, i, 0);
    }
}

// 打印数组元素的函数
void printArray(std::vector &arr) {
    for (int i : arr)
        std::cout << i << " ";
    std::cout << "\n";
}

// 测试代码
int main() {
    std::vector arr = {12, 11, 13, 5, 6, 7};
    heapSort(arr);
    std::cout << "Sorted array is \n";
    printArray(arr);
}

归并排序 (Merge Sort)

归并排序是一种分而治之的算法,通过递归方式将数组分成两半,分别对这两半进行排序,然后合并成一个有序数组。

步骤:
  1. 分割:将数组从中间分成两半,直到每个子数组只有一个元素或为空。
  2. 合并:逐步合并子数组,确保每次合并后都是有序的。
时间复杂度:
  • O(n log n)(在所有情况下)
空间复杂度:
  • O(n)(需要额外的空间来合并数组)

        归并排序是一种分而治之的算法,通过将数组分成两半并递归排序,然后合并结果。

#include 
#include 

// 合并两个子数组的函数
void merge(std::vector &arr, int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;

    // 创建临时数组
    std::vector L(n1), R(n2);

    // 复制数据到临时数组
    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];

    // 合并临时数组
    int i = 0, j = 0, k = l;

    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    // 复制 L[] 的剩余元素
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }

    // 复制 R[] 的剩余元素
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

// 主归并排序函数
void mergeSort(std::vector &arr, int l, int r) {
    if (l >= r) {
        return; // 如果只有一个元素
    }
    int m = l + (r - l) / 2;
    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);
    merge(arr, l, m, r);
}

// 打印数组的函数
void printArray(std::vector &arr) {
    for (int i : arr)
        std::cout << i << " ";
    std::cout << "\n";
}

// 测试代码
int main() {
    std::vector arr = {12, 11, 13, 5, 6, 7};
    mergeSort(arr, 0, arr.size() - 1);
    std::cout << "Sorted array is \n";
    printArray(arr);
}

二分查找 (Binary Search)

二分查找是一种在有序数组中查找特定元素的高效算法。它通过比较数组的中间元素与目标值,来减少搜索范围的一半。

步骤:
  1. 初始设置:设置两个指针,一个指向数组的起始位置,另一个指向数组的结束位置。
  2. 循环搜索:在指针指向的范围内,找到中间元素,并与目标值比较:
    • 如果中间元素等于目标值,则找到目标,返回其索引。
    • 如果中间元素大于目标值,则调整结束指针到中间指针之前。
    • 如果中间元素小于目标值,则调整起始指针到中间指针之后。
  3. 重复:重复步骤 2,直到找到目标或指针重合。
时间复杂度:
  • O(log n)
空间复杂度:
  • O(1)

        二分查找是在已排序数组中查找特定元素的高效方法。

#include 
#include 

// 二分查找函数
int binarySearch(const std::vector &arr, int x) {
    int l = 0, r = arr.size() - 1;
    while (l <= r) {
        int m = l + (r - l) / 2;

        // 检查元素是否在中间
        if (arr[m] == x)
            return m;

        // 如果元素大于中间,它只可能在右子数组
        if (arr[m] < x)
            l = m + 1;
        // 否则,元素只可能在左子数组
        else
            r = m - 1;
    }

    // 如果元素不在数组中
    return -1;
}

// 测试代码
int main() {
    std::vector arr = {2, 3, 4, 10, 40};
    int x = 10;
    int result = binarySearch(arr, x);
    if (result == -1)
        std::cout << "Element is not present in array";
    else
        std::cout << "Element is present at index " << result;
    return 0;
}

面试中的应用

        在面试中,你可能不仅要写出这些算法的代码,还需要解释其工作原理和性能特点。对于更高级的面试,你可能需要讨论这些算法的变种,或者在特定情景下如何优化它们。例如,对于堆排序,你可能会被问到如何处理大数据集,或者在归并排序中如何减少内存使用等。

你可能感兴趣的:(c++,面试,算法)