数据结构强化篇

应用题

排序


插入排序

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); // 归并
    }
}

效率分析

查找

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

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

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

相关推荐
汇能感知2 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun2 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao2 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾3 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT3 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
ST.J3 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin4 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全
小憩-4 小时前
【机器学习】吴恩达机器学习笔记
人工智能·笔记·机器学习
UQI-LIUWJ5 小时前
unsloth笔记:运行&微调 gemma
人工智能·笔记·深度学习
googleccsdn5 小时前
ESNP LAB 笔记:配置MPLS(Part4)
网络·笔记·网络协议