zoukankan      html  css  js  c++  java
  • 算法数据结构03 /二分查找、排序算法

    算法数据结构03 /二分查找、排序算法

    1. 二分查找

    • 二分查找:只能作用在有序集合

    • 代码实现:

      def middle(alist,item):
          find = False
          low = 0
          high = len(alist)-1
          
          while not find and low <= high:  # 要加=号
              mid = (low+high)//2 # 中间元素下标
              # 查找的值大于中间元素的值,意味着查找的值只可能出现在中间值的右侧
              if item > alist[mid]:
                  low = mid + 1
              # 查找的值和中间元素相等,意味着找到了
              elif item == alist[mid]:
                  find = True
              # 查找的值小于中间元素的值,意味着查找的值只可能出现在中间值的左侧 
              else: 
                  high = mid - 1
          return find
      
      alist = [1,2,3,4,5,6,7]
      print(middle(alist,5))
      

    2. 排序算法

    • 冒泡排序

      将乱序列表中的最大值逐步找出,将最大值最终移动到最后的位置

      1.实现将最大的数移到最右边

      def sort(alist):
          for i in range(0,len(alist)-1):  # 循环n-1次,n就是列表元素的个数
              if alist[i] > alist[i+1]:
                  alist[i],alist[i+1] = alist[i+1],alist[i]
          print(alist)
      
      alist = [3,8,6,7,5]
      sort(alist)
      
      # 结果:[3, 6, 7, 5, 8]
      

      2.实现冒泡排序:将上述操作逐步作用(n-1)次

      def sort(alist):
          for j in range(0,len(alist)-1):
              for i in range(0,len(alist)-1-j):  # 循环n-1次,n就是列表元素的个数
                  if alist[i] > alist[i+1]:
                      alist[i],alist[i+1] = alist[i+1],alist[i]
          return alist
      
      alist = [3,8,6,7,5]
      print(sort(alist))
      
      # 结果:[3, 5, 6, 7, 8]
      

      3.时间复杂度:

      • 最优时间复杂度:O(n)
      • 最坏时间复杂度:O(n2)
      • 平均时间复杂度:O(n2)
      • 稳定性:稳定

      冒泡

    • 选择排序

      直接将列表中最大值找出,直接放置到列表的最后的位置

      1.直接找出列表中的最大值,移到列表最后位置

      def sort(alist):
          max_index = 0  # 最大值的下标,一开始假设第0个元素是最大值
          for i in range(0,len(alist)-1):  # 为了找出最大值的下标
              if alist[max_index] < alist[i+1]:
                  max_index = i + 1
          alist[max_index],alist[len(alist)-1] = alist[len(alist)-1],alist[max_index]
          return alist
      

      2.实现选择排序:将上述操作再逐步的作用

      def sort(alist):
          for j in range(0,len(alist)-1):
              max_index = 0  # 最大值的下标,一开始假设第0个元素是最大值
              for i in range(0,len(alist)-1-j):  # 为了找出最大值的下标
                  if alist[max_index] < alist[i+1]:
                      max_index = i + 1
              alist[max_index],alist[len(alist)-1-j] = alist[len(alist)-1-j],alist[max_index]
          return alist
      
      alist = [3,8,6,7,5]
      print(sort(alist))
      
      # 结果:[3, 5, 6, 7, 8]
      

      3.时间复杂度:

      • 最优时间复杂度:O(n2)
      • 最坏时间复杂度:O(n2)
      • 平均时间复杂度:O(n2)
      • 稳定性:不稳定

      选择排序

    • 插入排序

      假设将列表分成两部分,第一部分为列表的第一个元素(有序序列),剩下的元素(无序序列),将无序序列的元素逐一的插入到有序序列的合适位置

      1.有序序列元素只有一个

      # 变量i表示列表下标,还表示有序序列中元素的个数
      # 有序序列只有一个元素,无序序列有n-1个元素
      i = 1  
      # alist[i] 表示的是无需序列的第一个元素
      # alist[i-1]  表示的是有序序列的最后一个元素
      if alist[i] < alist[i-1]:
          alist[i],alist[i-1] = alist[i-1],alist[i]
      

      2.有序序列元素有两个

      i = 2  # 表示有序序列有两个元素
      # alist[i] 表示的是无需序列的第一个元素
      # alist[i-1]  表示的是有序序列的最后一个元素
      while i>1:
          if alist[i] < alist[i-1]:
              alist[i],alist[i-1] = alist[i-1],alist[i]
              i -= 1
          else:
              break
      

      3.实现插入排序:完整代码,自动处理i (len-1)

      def sort(alist):
          for i in range(1,len(alist)):
              while i >= 1:
                  if alist[i] < alist[i-1]:
                      alist[i],alist[i-1] = alist[i-1],alist[i]
                      i -= 1
                  else:
                      break
          return alist
      
      alist = [49,38,65,97,76,13,27]
      print(sort(alist))
      
      # 结果:[13, 27, 38, 49, 65, 76, 97]
      

      4.时间复杂度:

      • 最优时间复杂度:O(n)
      • 最坏时间复杂度:O(n2)
      • 平均时间复杂度:O(n2)
      • 稳定性:稳定

      插入排序

    • 希尔排序

      插入排序就是增量为1的希尔排序

      增量(gap):初始值是元素个数整除2,还可以表示分组的组数(假设)

      1.实现步骤简述

      1.先增量初始值进行分组
      2.每组进行一次插入排序
      3.再缩小增量
      4.再进行每组的插入排序
      5.直到增量为1
      6.最后进行插入排序
      

      2.将插入排序的增量1变成gap

      def sort(alist):
          gap = len(alist)//2
          # 将下属所有的1换成gap
          for i in range(gap,len(alist)):
              while i >= gap:
                  if alist[i] < alist[i-gap]:
                      alist[i],alist[i-gap] = alist[i-gap],alist[i]
                      i -= gap
                  else:
                      break  
          return alist
      

      3.实现希尔排序:缩减增量

      def sort(alist):
          gap = len(alist)//2
          while gap >= 1:
              # 将下属所有的1换成gap
              for i in range(gap,len(alist)):
                  while i >= gap:
                      if alist[i] < alist[i-gap]:
                          alist[i],alist[i-gap] = alist[i-gap],alist[i]
                          i -= gap
                      else:
                          break
              gap //= 2 # 缩减增量            
          return alist
      
      alist = [49,38,65,97,76,13,27]
      print(sort(alist))
      
      # 结果:[13, 27, 38, 49, 65, 76, 97]
      

      5.时间复杂度:

      • 最优时间复杂度:O(n1.3)
      • 最坏时间复杂度:O(n2)
      • 平均时间复杂度:O(nlogn)
      • 稳定性:不稳定

      希尔排序

    • 快速排序

      有点类似二分查找

      基数:初始值就是列表中的第一个元素

      操作:将整个列表元素中比基数小的值全部放置到基数的左侧,将比基数大的放到基数的右侧

      定义两个变量:
      low :第0个元素的下标
      high:最后一个元素下标

      1.实现快速排序

      def sort(alist,start,end):
          low = start
          high = end
          if low > high:   # 结束递归的条件
              return
          
          mid = alist[low]  # 基数
          while low < high:
              while low < high:
                  if alist[high] > mid:
                      high -= 1  # high向左偏移
                  else:
                      alist[low] = alist[high]
                      break
              while low < high:
                  if alist[low] < mid:
                      low += 1
                  else:
                      alist[high] = alist[low]
                      break
          if low == high:
              alist[low] = mid
          sort(alist,start,high-1)  # 处理基数左部分的乱序序列
          sort(alist,low+1,end)  # 处理基数右部分的乱序序列
          return alist
      
      alist = [49,38,65,97,76,13,27]
      print(sort(alist,0,len(alist)-1))
      
      # 结果:[13, 27, 38, 49, 65, 76, 97]
      

      2.时间复杂度:

      • 最优时间复杂度:O(nlogn)
      • 最坏时间复杂度:O(n2)
      • 平均时间复杂度:O(nlogn)
      • 稳定性:不稳定

      快速排序

    • 归并排序

      归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。

      将数组分解最小之后,然后合并两个有序数组,基本思路就是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另外一个数组的剩余部分复制过来即可。

      归并排序相对于别的排序算法比较浪费空间,因为是重新生成了一个新的空间。

      1.代码实现归并排序:

      def merge_sort(alist):
          """ 归并排序 """
          n = len(alist)
          if n <= 1:
              return alist
          mid = n//2
          # left 采用归并排序后形成的有序的新的列表
          left_li = merge_sort(alist[:mid])
          # right 采用归并排序后形成的有序的新的列表
          right_li = merge_sort(alist[mid:])
          
          # 将两个有序的子序列合并为一个新的整体
          # merge(left,right)
          left_pointer, right_pointer = 0,0
          result = []
          while left_pointer<len(left_li) and right_pointer<len(right_li):
              if left_li[left_pointer] < right_li[right_pointer]:
                  result.append(left_li[left_pointer])
                  left_pointer += 1
              else:
                  result.append(right_li[right_pointer])
                  right_pointer += 1
          result += left_li[left_pointer:]
          result += right_li[right_pointer:]
          return result
      

      2.时间复杂度:

      • 最优时间复杂度:O(nlogn)
      • 最坏时间复杂度:O(nlogn)
      • 平均时间复杂度:O(nlogn)
      • 稳定性:稳定

    3.排序算法总结

  • 相关阅读:
    1002 写出这个数
    1001 害死人不偿命的(3n+1)猜想
    Graph I
    Tree
    进程通信
    管道
    fork函数
    Priority Queue
    Search
    游戏 slider
  • 原文地址:https://www.cnblogs.com/liubing8/p/12061623.html
Copyright © 2011-2022 走看看