首页 > 其他分享 >排序 - 插入排序

排序 - 插入排序

时间:2023-12-04 17:11:59浏览次数:28  
标签:dk 插入排序 插入 算法 排序 复杂度

插入排序

直接插入排序

算法描述

将一条记录插入到有序表中,得到新的有序表。
将需要调整位置的元素暂存在r[0]处,然后再进行插入。

算法实现

void InsertSort(SqList &L) {
    for(i = 2; i <= L.length; i++)
        if(L.r[i].key < L.r[i - 1].key) {
            L.r[0] = L.r[i]; L.r[i] = L.r[i - 1];
            for(j = i - 2; L.r[0].key < L.r[j].key; j--) 
                L.r[j + 1] = L.r[j]; // 逐个后移 找到插入位置
            L.r[j + 1] = L.r[0];
        }
}

算法分析

  1. 时间复杂度
    关键字比较次数KCN + 记录移动次数RMN = O(n²)
  2. 空间复杂度
    只需要一个辅助空间r[0],空间复杂度是O(1)

算法特点

  1. 稳定排序。
  2. 也适用于链式存储。
  3. 适用于初始记录基本有序的情况。

折半插入排序

算法描述

将直接插入排序的查找方式改为折半排序,提高平均性能。

算法实现

void BInsertSort(SqList &L) {
    for(i = 2; i <= L.length; i++) {
        L.r[0] = L.r[i];
        low = 1; high = i - 1;
        while(low <= high) {
            m = (low + high) / 2;
            if(L.r[0].key < L.r[m].key) high = m - 1;
            else low = m + 1;
        }
        for(j = i - 1; j >= high + 1; j--)
            L.r[j + 1] = L.r[j];
        L.r[high + 1] = L.r[0];
    }
}

算法分析

  1. 时间复杂度
    折半插入的查找比直接插入快,但无法减少移动次数。
    插入第i个记录时需要经过floor(log2(i) + 1)次比较。
    关键字比较次数KCN + 记录移动次数RMN = O(n²)
  2. 空间复杂度
    只需要一个辅助空间r[0],空间复杂度是O(1)

算法特点

  1. 稳定排序。
  2. 不适用于链式存储。
  3. 适用于初始记录无序、n较大的情况。

希尔排序

算法描述

本质上是一种分组插入
事先确定一个增量数组,每次取出一个增量d,把所有间隔为d的元素分成一组,全部元素共分成d组,在每个组中分别进行直接插入排序。
直接插入排序是一种增量为1的希尔排序。

算法实现

void ShellInsert(SqList &L, int dk) {
    for(i = dk + 1; i <= L.length; i++)
        if(L.r[i].key < L.r[i - dk].key) {
            L.r[0] = L.r[i];
            for(j = i - dk; j > 0 && L.r[0].key < L.r[j].key; j -= dk)
                L.r[j + dk] = L.r[j]; // 找到插入位置
            L.r[j + dk] = L.r[0];
        }
}

void ShellSort(SqList &L, int dt[], int t) {
    for(k = 0; k < t; k++)
        ShellInsert(L, dt[k]); // 增量为dt[t]
}

算法分析

  1. 时间复杂度
    低于直接插入排序,具体难以计算,但n取向无穷时,时间复杂度为n(log2(n))²
  2. 空间复杂度
    只需要一个辅助空间r[0],空间复杂度是O(1)

算法特点

  1. 不稳定排序。
  2. 不适用于链式存储。
  3. 增量值互质,必须递减,最后一个增量值必须为1.
  4. 适用于初始记录无序、n较大的情况。

标签:dk,插入排序,插入,算法,排序,复杂度
From: https://www.cnblogs.com/ww0809/p/17874678.html

相关文章

  • AcWing 785. 快速排序
    题面:给定你一个长度为\(n\)的整数数列。请你使用快速排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。原题链接:785.快速排序-AcWing需要注意的几个点:左右哨兵的发动顺序;相同元素的相对位置;边界划分问题[1]。#include<bits/stdc++.h>usingna......
  • 详解十大经典排序算法(三):插入排序(Insertion Sort)
    算法原理每次从无序部分选择一个元素,将其插入到有序部分的正确位置,重复这个过程直至整个数组有序。算法描述插入排序是一种简单直观的排序算法,它的基本思想是将一个待排序的元素插入到已经排序好的序列中的适当位置,从而得到一个新的、长度加一的有序序列。插入排序的过程类似于整理......
  • 算法之快速排序2基准元素的选择
    一:概述基准元素,英文是pivot,在分治的过程中,基准元素为中心,把其他的元素移动到它的左右两边。二:具体说明最简单的方式就是选择数列的第1个元素。这种选择在绝大多数情况下是没有问题的。但是,假如有一个原本逆序的数列,期望排列成顺序数列,那会出现什么情况呢?整个数列被分成了两部分,每一......
  • C语言冒泡排序法
    引言冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。冒泡的实现在细节上可以有很多种变化。最简单排序实现/*对顺序表L做交换排序*/voidBubbleSortO(SqList*L){ inti,j;for(i=1;i<L->length;i++) { fo......
  • 链表为什么适合归并排序而不是快速排序?
    链表适合归并排序而不是快速排序的原因主要有以下几点:内存访问模式:快速排序的效率主要来源于引用的局部性,计算机硬件在这里得到了优化,因此访问彼此相邻的内存位置往往比访问分散在内存中的内存位置更快。然而,链表单元格经常分散在内存中,所以访问相邻的链表单元格没有局部性......
  • 堆排序
    目录1.基本原理2.例子3.代码实现本文主要介绍堆排序的原理、例子以及代码实现。1.基本原理堆排序(HeapSort)是一种基于比较的排序算法,它的工作原理是首先将待排序的序列构造成一个大顶堆或小顶堆,然后交换堆顶元素和最后一个元素,然后将剩余元素重新调整为大顶堆或小顶堆,再交换堆......
  • Javascript实现快速排序Quicksort
    "快速排序"的思想很简单,整个排序过程只需要三步:(1)在数据集之中,选择一个元素作为"基准"(pivot)。(2)所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。(3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。代码实现......
  • 详解十大经典排序算法(二):选择排序(Selection Sort)
    算法原理选择排序通过重复选择数组中最小元素,将其与未排序部分的第一个元素交换,实现排序。算法描述选择排序是一种简单的排序算法,它每次从待排序的元素中选择最小(或最大)的元素,将其放到已排序序列的末尾,直到整个序列排序完成。选择排序的基本思想是通过不断选择剩余元素中的最小(或......
  • 希尔排序
      ......
  • 算法之快速排序1初始(java)
    一:概述快速排序、归并排序、堆排序等都是比冒泡排序更快的算法。其中快速排序是从冒泡排序演变而来。快速排序之所以比冒泡排序要快是因为它用了分治法。    二:具体说明同冒泡排序一样,快速排序也属于交换排序,通过元素之间的比较进行比较和交换位置来达到排序的目的。不同的是......