数据结构强化篇

应用题

排序


插入排序

cpp 复制代码
void InsertSort (ElemType A[], n int) {
    int i, j;
    for (i=2; i<=n; i++) //依次将 A[2]~A[n]插入前面已排序序列
        if (A[i]<A[i-1]) { //若 A[i]关键码小于其前驱,将 A[i]插入有序表
            A[0]=A[i]; //复制为哨兵,A[0]不存放元素
            for (j=i-1; A[0]<A[j]; --j) //从后往前查找待插入位置
                A[j+1]=A[j]; //向后挪位
            A[j+1]=A[0]; //复制到插入位置
        }
}

简单选择排序

思想:

每次从未排序的记录中选取最小关键字的记录,通过交换位置,加入已排序记录的末尾。

cpp 复制代码
void SelectSort (ElemType A[], int n) {
    for (int i=0; i<n-1; i++) { //一共进行 n-1 趟
        int min=i;
        for (int j=i+1; j<n; j++) //在 A[i...n-1]中选择最小的元素
            if (A[j]<A[min]) min=j; //更新最小元素位置
        if (min!=i) swap (A[i],A[min]); //封装的 swap()函数共移动元素 3 次
    }
}

冒泡排序

  1. 从最后(最前)两个开始,两两比较,每次把最小的交换到前面。
  2. 每一趟都会确定一个元素的最终位置。
  3. 如果本趟和上一趟相同,就结束排序
  4. 是稳定的排序算法(两个元素大小相等不会交换)。
cpp 复制代码
void BubbleSort (ElemType A[], int n) {
    for (int i=0; i<n-1; i++) {
        bool flag=false; //表示本趟冒泡是否发生交换的标志
        for (int j=n-1; j>i; j--) //一趟冒泡过程
            if (A[j-1]>A[j]) {
                swap(A[j-1],A[j]); //使用封装的 swap 函数交换
                flag=true;
            }
        if (flag==false) return; //本趟遍历后没有发生交换,说明表已经有序
    }
}

快速排序

思想:

  1. 从待排序的元素中选取一个基准元素,将所有比基准元素大的,放在右边,小的,放在左边。
  2. 先移动hight, 当找到小于基准元素的元素时,就将其放到low位置,然后再移动low,直到low==hight。
  3. 然后对左右两个子表进行递归。

效率分析:

快排的时间复杂度为 :n*递归深度

因此,快排的速度与递归搜索树的高度息息相关。

cpp 复制代码
// 用第一个元素将待排序序列划分成左右两个部分
int Partition(int A[], int low, int high) {
    int pivot = A[low]; // 第一个元素作为枢轴
    while (low < high) { // 用 low、high 搜索枢轴的最终位置
        while (low < high && A[high] >= pivot) --high;
        A[low] = A[high]; // 比枢轴小的元素移动到左端
        while (low < high && A[low] <= pivot) ++low;
        A[high] = A[low]; // 比枢轴大的元素移动到右端
    }
    A[low] = pivot; // 枢轴元素存放到最终位置
    return low; // 返回存放枢轴的最终位置
}

// 快速排序
void QuickSort(int A[], int low, int high) {
    if (low < high) { // 递归跳出的条件
        int pivotpos = Partition(A, low, high); // 划分
        QuickSort(A, low, pivotpos - 1); // 划分左子表
        QuickSort(A, pivotpos + 1, high); // 划分右子表
    }
}

归并排序

思想

  1. 假设两个有序序列,每次将i和j所指向元素中的最小元素插入k所指位置,k后移。
  2. 当一个序列所有元素插完后,就将另一个序列所有剩余元素插入到我们生成的有序序列末尾。
  3. 因此,当给我们一个无序序列时,我们可以先将所有元素两两一组,进行排序,然后递归合并。

代码实现

cpp 复制代码
int *B = (int *)malloc(n * sizeof(int)); // 辅助数组B

// A[low...mid]和A[mid+1...high]各自有序,将两个部分归并
void Merge(int A[], int low, int mid, int high) {
    int i, j, k;
    for (k = low; k <= high; k++) // 将A中所有元素复制到B中
        B[k] = A[k];
    for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
        if (B[i] <= B[j])
            A[k] = B[i++]; // 将较小值复制到A中
        else
            A[k] = B[j++];
    }
    // for
    while (i <= mid) A[k++] = B[i++];
    while (j <= high) A[k++] = B[j++];
}

void MergeSort(int A[], int low, int high) {
    if (low < high) {
        int mid = (low + high) / 2; // 从中间划分
        MergeSort(A, low, mid); // 对左半部分归并排序
        MergeSort(A, mid + 1, high); // 对右半部分归并排序
        Merge(A, low, mid, high); // 归并
    }
}

效率分析

查找

线性探测法与链地址法区别:

线性探测法:空的位置也算一次比较,因为是用顺序表存储的,因此,空的位置实际上是用一个特殊元素标记,比较发现是表示空的元素,因此算一次比较。

链地址法:由于指针是不能进行比较的,所以当发现一个关键字后面的指针为空时,就不再进行比较。

相关推荐
ZC跨境爬虫8 小时前
跟着 MDN 学 HTML day_9:(信件语义标记)
前端·css·笔记·ui·html
OBiO201312 小时前
Cell | 突破AAV载体容量限制!路中华/姜玉武/刘太安团队开发AAVLINK系统实现大基因递送
笔记
智者知已应修善业12 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
sakiko_13 小时前
UIKit学习笔记5-使用UITableView制作聊天页面
笔记·学习·swift·uikit
Alice-YUE14 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
小陈phd15 小时前
TensorRT 入门完全指南(一)——从核心定义到生态工具全解析
人工智能·笔记
是上好佳佳佳呀15 小时前
【前端(十一)】JavaScript 语法基础笔记(多语言对比)
前端·javascript·笔记
handler0115 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
其实防守也摸鱼16 小时前
CTF密码学综合教学指南--第四章
网络·笔记·安全·网络安全·密码学·ctf
05候补工程师18 小时前
【ROS 2 具身智能】Gazebo 仿真避坑指南:从“幽灵机器人”到传感器数据流打通
人工智能·经验分享·笔记·ubuntu·机器人