各色各样的排序

简单选择排序:


初始:[5 4 6 8 7 1 2 3]
第一趟排序后 1 [4 6 8 7 5 2 3]
第二趟排序后 1 2 [6 8 7 5 4 3]
第三趟排序后 1 2 3 [8 7 5 4 6]
第四趟排序后 1 2 3 4 [7 5 8 6]
第五趟排序后 1 2 3 4 5 [7 8 6]
第六趟排序后 1 2 3 4 5 6 [8 7]
第七趟排序后 1 2 3 4 5 6 7 [8]
最后排序结果 1 2 3 4 5 6 7 8

python源码:

def selection_sort(a):
  n = len(a)
  for i in range(n - 1):
      k = i
      for j in range(i + 1, n):
          if a[j] < a[k]:
              k = j
      if k != i:
          temp = a[i]
          a[i] = a[k]
          a[k] = temp


arr = [5 ,4 ,6 ,8 ,7, 1, 2 ,3]

selection_sort(arr)
print(arr)

冒泡排序:

  初始数据:4 5 6 1 2 3
  第一趟:
  比较前两个数,   4比5小,交换位置     5 4 6 1 2 3
  比较第2第3个数, 4比6小,交换位置     5 6 4 1 2 3
  比较第3第4个数, 5比1大,位置不变     5 6 4 1 2 3
  比较第4第5个数, 1比2小,交换位置     5 6 4 2 1 3
  比较最后两个数, 1比3小,交换位置     5 6 4 2 3 1
  第一趟结束

  第二趟重复第一趟过程得到 6 5 4 3 2 1
  排序完毕。

python源码:

def BubbleSort(arr):
  n = len(arr)
  for i in range(n-1):  # 遍历所有数组元素
      for j in range(0, n - i - 1):
          if arr[j] > arr[j + 1]:
              arr[j], arr[j + 1] = arr[j + 1], arr[j]


arr = [4, 5, 6, 1, 2, 3]

BubbleSort(arr)
print(arr)

 桶排序:

  • 基本思想

桶排序的思想是,若待排序的记录的关键字在一个明显有限范围内时,可设计有限个有序桶,每个桶只能装与之对应的值,顺序输出各桶的值,将得到有序的序列。简单来说,在我们可以确定需要排列的数组的范围时,可以生成该数值范围内有限个桶去对应数组中的数,然后我们将扫描的数值放入匹配的桶里的行为,可以看作是分类,在分类完成后,我们需要依次按照桶的顺序输出桶内存放的数值,这样就完成了桶排序。

例如,要求我们输入 n 个 0~9 之间的整数,由小到大排序输出,我们可以准备 10 个桶依次编号为 0~9。那么,输入的数 0 则入 0 号桶,1 入 1 号桶,依次类推。

  • 如图所示

如上图所示,我们已准备好 10 个空桶并编号。

下面我们依次输入 8 个整数,分别是 2,5,6,8,5,2,9,6,我们每输入一个数值就将其放入对应的桶。

输入完毕后桶内数据如图所示:

桶排序过程:

  • 如上图所示,2 号桶内有两个数字 2,5 号桶内有两个数字 5,6 号桶内有两个数字 6,8 号桶内有一个数字 8,9 号桶内有一个数字 9
  • 然后我们按桶编号从小到大的顺序将桶内数字输出,得到 2,2,5,5,6,6,8,9,至此桶排序完成。

注意,桶排序需要注意适用范围,在已知所需排序数据的范围下可以使用,另外咱们只讨论整型的情况。

python源码:

b={0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0}
n=eval(input("输入整数n"))
for i in range(n):
  x=eval(input("输入0~9之间的整数"))
  b[x]+=1
for key in range(10):
  while b[key]>0:
      print(key,end=' ')
      b[key]-=1

插入排序:

插入排序是一种简单的排序方法,时间复杂度为 O(n*n),适用于数据已经排好序,插入一个新数据的情况。其算法的基本思想是,假设待排序的数据存放在数组 a[1...n] 中,增加一个节点 x 用于保存当前数据,进行比较,a[1]即作为有序区,a[2...n] 作为无序区。

  • 从 i=2 起直至 i=n 为止,通过循环遍历,将 a[i] 放在恰当的位置,使 a[1...i] 数据序列有序。

x=a[i] 将 x 与前 i-1 个数比较

j=i-1
while(x<a[j])  j-= 1,
  
将 a 数组的元素从 j 位置开始向后移动:

for k in range(j,i+1,-1):  
 
 a[k]=a[k-1]
 a[j]=x

生成包含 n 个数据的有序区

例如,我们现在有一个数组 a=[3 2 4 1 6 5 2 7],需要使用插入排序进行排列。

排序过程:

第0步:[3] 2 4 1 6 5 2 7
第1步:[2 3] 4 1 6 5 2 7
第2步:[2 3 4] 1 6 5 2 7
第3步:[1 2 3 4] 6 5 2 7
第4步:[1 2 3 4 6] 5 2 7
第5步:[1 2 3 4 5 6] 2 7
第6步:[1 2 2 3 4 5 6] 7
第7步:[1 2 2 3 4 5 6 7]

 python源码:

def insertionSort(arr):
  for i in range(1, len(arr)):
     x = arr[i]
      j = i - 1
      while j >= 0 and x < arr[j]:
          arr[j + 1] = arr[j]
          j -= 1
      arr[j + 1] = x


arr = [0, 3, 2, 4, 1, 6, 5, 2, 7]

insertionSort(arr)
print(arr)

快速排序:

  • 基本思想

快速排序是一种采用分治法解决问题的一个典型应用,也是冒泡排序的一种改进。它的基本思想是,通过一轮排序将待排记录分割成独立的两部分,其中一部分均比另一部分小,则可分别对这两部分继续进行排序,已达到整个序列有序。排序的时间复杂度为 O(nlogn),相比于简单排序算法,运算效率大大提高。

  • 算法步骤
  1. 从序列中取出一个数作为中轴数;
  2. 将比这个数大的数放到它的右边,小于或等于他的数放到它的左边;
  3. 再对左右区间重复第二步,直到各区间只有一个数。

例如,对以下 10 个数进行快速排序:

6 1 2 7 9 3 4 5 10 8

以第一个数为基准数,在初始状态下,数字 6 在序列的第 1 位,我们的目标是将 6 挪到序列中间的某个位置,假设这个位置是 k 。

现在就需要寻找这个 k ,并且以第 k 位为分界点,左边的数都≤6,右边的数都≥6。那么如何找到这个位置 k 呢?

我们要知道,快速排序其实是冒泡排序的一种改进,冒泡排序每次对相邻的两个数进行比较,这显然是一种比较浪费时间的。

而快速排序是分别从两端开始”探测”的,先从右往左找一个小于 6 的数,再从左往右找一个大于 6 的数,然后交换他们。这里可以用两个变量 i 和 j ,分别指向序列最左边和最右边。

我们为这两个变量起个好听的名字哨兵 i 和哨兵 j

  1. 我们首先让哨兵 i 指向序列的最左边,指向数字 6;让哨兵 j 指向序列的最右边,指向数字 8,如下图所示。

图8.3 快速排序初始状态

  1. 首先哨兵 j 开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵 j 先出动,这一点非常重要。
  • 哨兵 j 一步一步地向左挪动,直到找到一个小于 6 的数停下来
  • 然后哨兵 i 再一步一步向右挪动,直到找到一个数大于 6 的数停下来
  1. 最后哨兵 j 停在了数字 5 面前,哨兵 i 停在了数字 7 面前,如下图所示:

图8.4 快速排序过程

  1. 现在交换哨兵 i 和哨兵 j 所指向元素的值,交换之后的序列如下:

在这里插入图片描述

  1. 到此,第一次交换结束。接下来开始哨兵 j 继续向左挪动(再友情提醒,每次必须是哨兵 j 先出发)。他发现了 4<6,停下来。哨兵 i 也继续向右挪动的,他发现了 9>6,停下来。此时再次进行交换,交换之后的序列如下

图8.6 快速排序过程

  1. 第二次交换结束。哨兵 j 继续向左挪动,他发现了 3<6,又停下来。

  2. 哨兵 i 继续向右移动,此时哨兵 i 和哨兵 j 相遇了,哨兵 i 和哨兵 j 都走到 3 面前。

说明此时“探测”结束。我们将基准数 6 和 3 进行交换。交换之后的序列如下。

图8.7 快速排序一趟结果

到此第一轮“探测”真正结束。

现在基准数 6 已经归位,此时以基准数 6 为分界点,6 左边的数都小于等于 6,6 右边的数都大于等于 6。

现在我们将第一轮“探测”结束后的序列,以 6 为分界点拆分成两个序列,左边的序列是“3 1 2 5 4”,右边的序列是“9 7 10 8”。接下来还需要分别处理这两个序列,因为 6 左边和右边的序列目前都还是混乱的。不过不要紧,我们已经掌握了方法,接下来只要模拟刚才的方法分别处理 6 左边和右边的序列即可。

python源码:

def qsort(a,l,r):
    if(l>r):
        return None
    tmp=a[l]    
    i=l
    j=r
    while i!=j:
        while(a[j]>=tmp and j>i):
            j-=1
        while(a[i]<=tmp and j>i):
            i+=1
        if(j>i):
            t=a[i]
            a[i]=a[j]
            a[j]=t
    a[l]=a[i]
    a[i]=tmp
    qsort(a,l,i-1)
    qsort(a,i+1,r)
a=[5,3,7,3,2]
qsort(a,0,4)
print(a)

归并排序:

  • 基本思想

归并排序是由递归实现的,主要是分而治之的思想,也就是通过将问题分解成多个容易求解的局部性小问题来解开原本的问题的技巧。

归并排序在合并两个已排序数组时,如果遇到了相同的元素,只要保证前半部分数组优先于后半部分数组, 相同元素的顺序就不会颠倒。所以归并排序属于稳定的排序算法。

每次分别排左半边和右半边,不断递归调用自己,直到只有一个元素递归结束,开始回溯,调用 merge 函数,合并两个有序序列,再合并的时候每次给末尾追上一个最大 int 这样就不怕最后一位的数字不会被排序。

  • 排序过程

 python代码实现:

def MergeSort(lists):
  if len(lists) <= 1:
      return lists
  num = int( len(lists) / 2 )
  left = MergeSort(lists[:num])
  right = MergeSort(lists[num:])
  return Merge(left, right)
def Merge(left,right):
  r, l=0, 0
  result=[]
  while l<len(left) and r<len(right):
      if left[l] <= right[r]:
          result.append(left[l])
          l += 1
      else:
          result.append(right[r])
          r += 1
  result += list(left[l:])
  result += list(right[r:])
  return result

if __name__=='__main__':

a=[1, 2, 3, 4, 5, 6, 7, 90, 21, 23, 45]
a=MergeSort(a)

print (a)

 希尔排序:

  • 基本思想

    希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法,同时也突破了之前内排序算法复杂度为 O(n2)的限制。

    希尔排序是基于插入排序的以下两点性质而提出改进方法的:

    • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率.
    • 插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

该方法的基本思想是:

先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。

其中增量序列的选择是非常关键的,但通常我们取步长为 n/2(数组长度的一般)然后一直取半直到 1。

python源码实现:

a = [56,52,-96,-53,23,-789,520]    #测试案例
b = len(a)                         #列表长度
gap = b // 2                       #初始步长设置为总长度的一半
while gap >= 1:
  for i in range (b):
      j = i
      while j>=gap and a[j-gap] > a[j]:   #在每一组里面进行直接插入排序
          a[j],a[j-gap] = a[j-gap],a[j]
          j-= gap
  gap=gap//2                              #更新步长
print(a)

 

 

注: 文章内容摘自该链接文档,多此一举,实为共同学习、知识共享:蓝桥杯省赛 14 天夺奖冲刺营 - 练一练「弗里石的的语言」 - 蓝桥云课 (lanqiao.cn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古剑诛仙

你的鼓励是我创造的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值