【12】数据结构之基于线性表的排序算法

目录标题

插入排序

  • 基本思想:将一个元素插入到一个有序序列中,继而得到一个有序的元素个数加一的新序列.

直接插入排序

  • 基本操作:将第i个元素插入前面i-1个已经排好序的序列中.
  • 示意图:举例序列(21,25,49,25,16,8)
python 复制代码
# 4-1.直接插入排序
class InsertSort:
    def __init__(self, items):
        self.items = items

    def insertSort(self):
        # 直接插入排序
        # 从第二个元素开始排序
        for i in range(1,len(self.items)):
            # 获取第n个元素
            temp = self.items[i]
            j = i-1
            while j >= 0 and temp < self.items[j]:
                self.items[j+1] = self.items[j]
                j -= 1
            self.items[j+1] = temp
            
if __name__ == '__main__':     
	# 4-1.直接插入排序
    print('直接插入排序:')
    nums = [21, 25, 49, 25, 16, 8]
    print(f"排序前情况:{nums}")
    select = InsertSort(nums)
    select.insertSort()
    print(f"直接插入排序后情况:{nums}")
  • 最好与最坏的直接插入排序法情况
    • 顺序排序:总的比较次数n-1次;总的移动次数2(n-1)次.
    • 逆序排序:总的比较次数(n-1)(n+2)/2;总的移动次数(n-1)(n+4)/2次.
  • 时间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)

折半插入排序

  • 基本操作:在直接插入排序中,可以在前半部分的有序序列中采用折半查找的方法以提高查找速度.
  • 折半插入排序在次数比较上减少了很多,但是时间复杂度仍然还是: O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 折半插入示意图
python 复制代码
# 4-2.折半插入排序
class BinaryInsertSort:
    def __init__(self, items):
        self.items = items  # 初始化待排序数组

    def binaryInsertSort(self):
        """折半插入排序"""
        for i in range(1, len(self.items)):  # 从第二个元素开始遍历
            temp = self.items[i]  # 当前待插入元素
            low = 0
            high = i - 1  # 已排序区间的右边界

            # ---------- 折半查找插入位置 ----------
            while low <= high:
                mid = (low + high) // 2
                if self.items[mid] > temp:
                    high = mid - 1  # 插入点在左半区
                else:
                    low = mid + 1  # 插入点在右半区
            # 最终插入位置为 high + 1

            # ---------- 元素后移 & 插入 ----------
            for j in range(i - 1, high, -1):  # 将 high+1 到 i-1 的元素后移
                self.items[j + 1] = self.items[j]
            self.items[high + 1] = temp  # 插入元素到正确位置
       
if __name__ == '__main__':  
	# 4-2.折半插入排序
    print('折半插入排序:')
    nums = [21, 25, 49, 25, 16, 8]
    print(f"排序前情况:{nums}")
    select = BinaryInsertSort(nums)
    select.binaryInsertSort()
    print(f"折半插入排序后情况:{nums}")
    print()

希尔排序

  • 基本操作
    • 先取一个小于n的整数d作为第一个增量,把序列的全部元素分为d个组.
    • 在各组内部进行直接插入排序.
    • 再取第二个增量d1(小于d),分为d1个组,在组内进行直接插入排序.
    • 重复,直至增量为1,完成排序.
  • 希尔排序示意图
python 复制代码
# 4-3.希尔排序
class ShellSort:
    def __init__(self, items):
        self.items = items

    def shellSort(self):
        if self.items is None or len(self.items) <= 1:
            return
        length = len(self.items)//4
        while length > 0:
            for left in range(len(self.items)):
                right = left - length
                while right >= 0:
                    if self.items[right] > self.items[right + length]:
                        self.items[right], self.items[right+length] = self.items[right+length],self.items[right]
                    right = right - length
            length //= 2

if __name__ == '__main__':
	# 4-3.希尔排序
    print('希尔排序:')
    nums = [46, 55, 13, 42, 94, 17, 5, 70]
    shell = ShellSort(nums)
    print(f"排序前情况:{nums}")
    shell.shellSort()
    print(f"希尔排序后情况:{nums}")
    print()
  • 运行情况

交换排序

  • 基本思想:根据序列中两个元素关键字的比较结果,判断是否需要交换元素在序列中的位置.

冒泡排序

  • 核心思想:
    • 反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若为逆序则交换位置.
    • 每一轮排序都将当前未排序的序列中的最大值下沉到最底部,直至得到有序序列.
  • 一轮冒泡排序示意图
python 复制代码
# 5-1.冒泡排序
class BubbleSort:
    def __init__(self, items):
        self.items = items

    def bubbleSort(self):
        if self.items is None or len(self.items) == 0:
            return
        for i in range(len(self.items)):
            for j in range(len(self.items)-1-i):
                if self.items[j] > self.items[j+1]:
                    self.items[j],self.items[j+1] = self.items[j+1], self.items[j]
                    
if __name__ == '__main__':
	# 5-1.冒泡排序
    print('冒泡排序:')
    nums = [21, 25, 49, 25, 16, 8]
    bubble = BubbleSort(nums)
    print(f"排序前情况:{nums}")
    bubble.bubbleSort()
    print(f"冒泡排序后情况:{nums}")
    print()  

快速排序

  • 核心思想
    • 是对冒泡排序的一种改进.
    • 算法以某一元素v作为基准,先将待排序序列分为前后两段(前段元素要求均小于v,后段元素要求均大于v),
    • 再分别对前段、后段元素进行快速排序,利用递归调用进行实现,
    • 重复进行,直至得到一个长度为n的有序序列.
  • 一轮快速排序示意图
powershell 复制代码
# 5-2.快速排序
class QuickSort:
    def __init__(self, items):
        self.items = items

    def quickSort(self):
        """快速排序入口方法"""
        self._sort(0, len(self.items) - 1)
        return self.items

    def _sort(self, left, right):
        """递归排序核心逻辑"""
        if left < right:
            pivot_index = self._partition(left, right)
            self._sort(left, pivot_index - 1)  # 递归处理左半部分
            self._sort(pivot_index + 1, right)  # 递归处理右半部分

    def _partition(self, left, right):
        """划分操作"""
        pivot = self.items[right]  # 选择最后一个元素为基准值
        i = left - 1  # 小于基准值的分界指针

        for j in range(left, right):
            if self.items[j] <= pivot:
                i += 1
                self.items[i], self.items[j] = self.items[j], self.items[i]  # 交换元素

        # 将基准值放到正确位置
        self.items[i + 1], self.items[right] = self.items[right], self.items[i + 1]
        return i + 1  # 返回基准值的最终位置
        
if __name__ == '__main__':
	# 5-2.快速排序
    print('快速排序:')
    nums = [21, 25, 49, 25, 16, 8, 34]
    quick = QuickSort(nums)
    print(f"排序前情况:{nums}")
    quick.quickSort()
    print(f"快速排序后情况:{nums}")
    print()
  • 交换排序的运行结果

归并排序

  • 核心思想
    • 将两个或两个以上有序序列合并成一个新的有序序列.
    • 初始序列含有n个元素,将每个元素看成n个有序子序列.
    • 进行两两归并,得到n/2的有序序列.
    • 递归调用,在之前的基础上,不断地进行两两归并.
    • 直到得到一个长度为n的有序序列.
    • 上述方法也成为2-路归并排序.
  • 2-路归并排序
python 复制代码
# 6.归并排序
class mergeSort:
    def merge(self, left, right):
        # 把多个有序序列合并成一个有序序列
        result = []
        left_index = 0
        right_index = 0
        while left_index < len(left) and right_index < len(right):
            if left[left_index] <= right[right_index]:
                result.append(left[left_index])
                left_index += 1
            else:
                result.append(right[right_index])
                right_index += 1
        # while循环结束,把剩下的数据添加进去
        result += right[right_index:]
        result += left[left_index:]
        return result

    def mergeSort(self, items):
        # 归并排序
        n = len(items)
        # 递归返回
        if n == 1:
            return items
        # 将数据分为左右两部分
        mid = n // 2
        left = items[:mid]
        right = items[mid:]
        # 递归拆分
        left_sort = self.mergeSort(left)
        right_sort = self.mergeSort(right)
        return self.merge(left_sort, right_sort)


if __name__ == '__main__':

    print('PyCharm')
    # 6.归并排序
    print('归并排序:')
    nums = [19, 13, 5, 27, 1,26, 31, 16]
    merge = mergeSort()
    print(f"排序前情况:{nums}")
    nums = merge.mergeSort(nums)
    print(f"归并排序后情况:{nums}")
    print()
  • 运行结果
  • 时间复杂度: O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)

时间复杂度对比

最好情况

  • 直接插入排序 O ( n ) \mathcal{O}(n) O(n)
  • 折半插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 希尔排序 O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
  • 冒泡排序 O ( n ) \mathcal{O}(n) O(n)
  • 快速排序 O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
  • 归并排序 O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)

平均情况

  • 直接插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 折半插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 希尔排序 O ( n 3 / 2 ) \mathcal{O}(n^{3/2}) O(n3/2)
  • 冒泡排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 快速排序 O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
  • 归并排序 O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)

最坏情况

  • 直接插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 折半插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 希尔排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 冒泡排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 快速排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
  • 归并排序 O ( n log ⁡ 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)

空间复杂度对比

  • 直接插入排序 O ( 1 ) \mathcal{O}(1) O(1)
  • 折半插入排序 O ( 1 ) \mathcal{O}(1) O(1)
  • 希尔排序 O ( 1 ) \mathcal{O}(1) O(1)
  • 冒泡排序 O ( 1 ) \mathcal{O}(1) O(1)
  • 快速排序 O ( log ⁡ 2 n ) ∼ O ( n ) \mathcal{O}(\log_2 n) \sim \mathcal{O}(n) O(log2n)∼O(n)
  • 归并排序 O ( n ) \mathcal{O}(n) O(n)
相关推荐
weixin_307779133 分钟前
Python Pandas实现导出两个Excel数据集的分组记录数分析
开发语言·python·pandas
踢足球的程序员·6 分钟前
OpenGL学习笔记(立方体贴图、高级数据、高级GLSL)
笔记·学习·图形渲染
King.6248 分钟前
行业深度:金融数据治理中的 SQL2API 应用创新
大数据·开发语言·数据库·人工智能·sql·金融
WarPigs9 分钟前
VRoid-Blender-Unity个人工作流笔记
笔记·blender
云之兕11 分钟前
MyBatis 详解
java·开发语言·mybatis
陌漠ardently16 分钟前
正则表达式和excel文件保存(python)
python·mysql·excel
2303_Alpha18 分钟前
深度学习入门:神经网络的学习
人工智能·python·深度学习·神经网络·学习·机器学习
Katherine_lin19 分钟前
JAVA:线程的状态与生命周期
java·开发语言
Q1860000000022 分钟前
如何把pdf的内容转化成结构化数据进行存储到mysql数据库
数据库·python·mysql·pdf
钮钴禄·爱因斯晨39 分钟前
深入理解 Java 内存区域与内存溢出异常
java·开发语言