文章来源于NewBeeNLP,作者kaiyuan

写在前面

看到好像春招都已经陆续都开始了,最近抽空打算把自己和朋友的经验整理一下分享出来。作为一个刚刚经历秋招打击的自闭儿童,可以非常负责任地说手撕算法是面试中必考的点,而且非常重要。

这一篇就从最常见的排序算法开始。

1.排序及其分类

所谓排序就是将一组无序的记录序列调整为有序的记录序列。

  • 选择排序:主要包括简单选择排序和堆排序

  • 插入排序:简单插入排序、希尔排序

  • 交换排序:冒泡排序、快速排序

  • 归并排序

  • 非比较排序:计数排序、桶排序、基数排序属于非比较排序,算法时间复杂度O(n), 属于空间换时间。

2. 经典排序的python实现

2.1 选择排序

从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部带排序的数据元素排完。

def select_sort(lists):n = len(list)for i in range(n):for j in range(i,n):if list[i]<list[j]:list[i],list[j]=list[j],list[i]return lists

2.2 插入排序

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据。算法适用于少量数据的排序,时间复杂度为O(n^2)。

插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。步骤如下:

  1. 假设序列的第一个数是排序好的,(如果序列长度为1,那就更好了,不用排序了)。

  2. 取出已排序的数的下一个数,当前这个数是需要排序的(未排序)。用当前这个数与之前排序好的数进行比较,比较的顺序是从后往前。

  3. 如果当前已经排序的数比未排序的数大,则已经排序的数往后挪一个位置,空出当前已经排序位置,下次比较的已经排序好的数是当前已经排序好的数的前一个数。

  4. 重复步骤3,直到未排序的数小于已排序的数,将未排序的数插入到空出的位置。

  5. 重复2-5 ,直到所有数都排序好

def insert_sort(lists):size = len(lists)for i in range(1, size):key = lists[i]j = i-1while j >= 0:if lists[j] > key:lists[j+1] = lists[j]lists[j] = keyj -= 1return lists

2.3 希尔排序

希尔排序是插入排序的一种。克服了插入排序每次只比较相邻元素的缺陷。

基本思想:

把记录按下标的一定增量进行分组,对每组直接使用插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

def shell_sort(lists):n =len(lists)dist = n // 2while dist>0:for i in range(dist,n):temp = lists[i]j = iwhile j >= dist and temp < lists[j-dist]:lists[j] = lists[j-dist]j -= distlists[j] = tempdist //= 2return lists

2.4 冒泡排序

重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

时间复杂度为O(n^2)

def bubble_sort(lists):n = len(lists)for i in range(n):for j in range(1, n-i):  # 每一次冒泡将最大的数交换到数列的最后一位if lists[j-1] > lists[j]:lists[j - 1],lists[j] = lists[j], lists[j-1]return lists

2.5 归并排序

基本思想:

将数组A[0...n-1]中的元素分成两个子数组,A1[0...n/2] 和A2[n/2+1...n-1]。分别对这两个子数组单独排序(递归),然后将已排序的两个子数组归并成一个含有n个元素的有序数组。

合并的过程:

比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。

def merge_sort(lst):if len(lst) <= 1:return lstmid = len(lst) //2left = merge_sort(lst[:mid])right = merge_sort(lst[mid:])return merge(left, right)def merge(left, right):res = []i = j = 0while i <len(left) and j <len(right):if left[i] <= right[j]:res.append(left[i])i += 1else:res.append(right[j])j += 1res += left[i:]res += right[j:]return res

2.6 堆排序

利用数组的特点快速定位指定索引的元素,堆分为大根堆和小根堆,是完全二叉树。

基本思想:

  1. 最大堆调整(adjust_heap): 将堆的末端子节点作调整,使得子节点永远小于父节点。这是核心步骤,在建堆和堆排序都会用到。比较i的根节点和与其所对应i的孩子节点的值。当i根节点的值比左孩子节点的值要小的时候,就把i根节点和左孩子节点所对应的值交换,当i根节点的值比右孩子的节点所对应的值要小的时候,就把i根节点和右孩子节点所对应的值交换。然后再调用堆调整这个过程,可见这是一个递归的过程。

  2. 建立最大堆(Build_Heap): 将堆所有数据重新排序。建堆的过程其实就是不断做最大堆调整的过程,从len/2出开始调整,一直比到第一个节点。

  3. 堆排序(Heap_Sort): 移除位在第一个数据的根节点,并做最大堆调整的递归运算。堆排序是利用建堆和堆调整来进行的。首先先建堆,然后将堆的根节点选出与最后一个节点进行交换,然后将前面len-1个节点继续做堆调整的过程。直到将所有的节点取出,对于n个数我们只需要做n-1次操作。

def heap_sort(lists):# 堆排序size = len(lists)build_heap(lists, size)for i in range(0, size)[::-1]:lists[0], lists[i] = lists[i], lists[0]adjust_heap(lists, 0, i)return listsdef adjust_heap(lists, i, size):# 调整堆lchild = 2 * i + 1rchild = 2 * i + 2maxi = iif lchild < size and lists[maxi] < lists[lchild]:maxi = lchildif rchild < size and lists[maxi] < lists[rchild]:maxi = rchildif maxi != i:# 如果做了堆调整则maxi的值等于左节点或者右节点的,这个时候做对调值操作lists[maxi], lists[i] = lists[i], lists[maxi]adjust_heap(lists, maxi, size)def build_heap(lists, size):# 堆的构建for i in range(0, int(size/2))[::-1]:adjust_heap(lists, i, size)

2.7 快速排序

快速排序是一种基于划分的排序方法,划分Partition思想:

选取待排序集合A中的某个元素t,按照与t的大小关系重新整理A中元素,使得整理后的序列中所有在t以前出现的元素均小于t,而所有出现在t以后的元素均大于等于t;元素t称为划分元素。反复地对A进行划分达到排序的目的。

划分算法:

对于数组A[0...n-1]:

  • 设置两个变量i, j:i=0, j=n-1

  • 以A[0]为关键数据,即key=A[0]

  • 从j开始向前搜索,直到找到第一个小于key的值a[j],将a[i] = a[j];

  • 从i开始向后搜索,直到找到第一个大于等于key的值a[i],a[j] = a[i];

  • 重复第3、4步,直到i≥j.

def quick_sort(lists):less = []pivotList = []more = []if len(lists) <= 1:return listselse:pivot = lists[0]  # 将第一个值作为基准值for i in lists:if i < pivot:less.append(i)elif i > pivot:more.append(i)else:pivotList.append(i)less = quick_sort(less)more = quick_sort(more)return less + pivotList + more
def QuickSort(myList,start,end):#判断low是否小于high,如果为false,直接返回if start < end:i,j = start,end#设置基准数base = myList[i]while i < j:#如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现while (i < j) and (myList[j] >= base):j = j - 1#如找到,则把第j个元素赋值给第个元素i,此时表中i,j个元素相等myList[i] = myList[j]#同样的方式比较前半区while (i < j) and (myList[i] <= base):i = i + 1myList[j] = myList[i]#做完第一轮比较之后,列表被分成了两个半区,并且i=j,需要将这个数设置回basemyList[i] = base#递归前后半区QuickSort(myList, start, i - 1)QuickSort(myList, j + 1, end)return myList

2.8 计数排序

基本思想: 对于每一个元素A[i],确定小于a[i]的元素个数。所以直接可以把a[I]放到输出数组的相应位置上,比如有5个数小于a[i],则a[i]应该放在输出数组的第六个位置上。

def count_sort(a, k):  # k = max(a)n = len(a)  # 计算a序列的长度b = [0 for i in range(n)]  # 设置输出序列并初始化为0c = [0 for i in range(k + 1)]  # 设置计数序列并初始化为0,for j in a:c[j] = c[j] + 1for i in range(1, len(c)):c[i] = c[i] + c[i-1]for j in a:b[c[j] - 1] = jc[j] = c[j] - 1return b

2.9 桶排序

基本思想: 把数组A划分为n个大小相同的区间(即桶),每个子区间各自排序,最后合并。桶排序要求数据的分布必须均匀,否则可能会失效。计数排序是桶排序的一种特殊情况,可以把计数排序当成每个桶里只有一个元素的情况。

def bucket_sort(a):buckets = [0] * ((max(a) - min(a)) + 1)  # 初始化桶元素为0for i in range(len(a)):buckets[a[i] - min(a)] += 1  # 遍历数组a,在桶的相应位置累加值b = []for i in range(len(buckets)):if buckets[i] != 0:b += [i + min(a)] * buckets[i]return b

2.10 基数排序

基本思想: 将待排序的数据按照位数切割成不同的数字,然后按每个位数分别比较。

基数排序可以采用两种方式:

  • LSD(Least Significant Digital):从待排序元素的最右边开始计算(如果是数字类型,即从最低位个位开始)。

  • MSD(Most Significant Digital):从待排序元素的最左边开始计算(如果是数字类型,即从最高位开始)。

def radix_sort(list, d=3): # 默认三位数,如果是四位数,则d=4,以此类推for i in range(d):  # d轮排序s = [[] for k in range(10)]  # 因每一位数字都是0~9,建10个桶for j in list:s[int(j / (10 ** i)) % 10].append(j)re = [a for b in s for a in b]return re

3.排序算法的比较

END -

往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习在线手册深度学习在线手册AI基础下载(pdf更新到25集)备注:本站qq群1003271085,加入本站微信群请回复“加群”获取一折本站知识星球优惠券,请回复“知识星球”喜欢文章,点个在看

【Kick Algorithm】十大排序算法及其Python实现相关推荐

  1. 数据结构十大排序算法(python)

    十大经典排序算法 (java实现看这个)https://program.blog.csdn.net/article/details/83785159 名词解释: 1.冒泡排序 2.选择排序 3.插入排 ...

  2. 八十八、Python | 十大排序算法系列(下篇)

    @Author:Runsen @Date:2020/7/10 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  3. 八十七、Python | 十大排序算法系列(上篇)

    @Author:Runsen @Date:2020/7/10 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  4. 一篇夯实一个知识点系列--python实现十大排序算法

    写在前面 排序是查找是算法中最重要的两个概念,我们大多数情况下都在进行查找和排序.科学家们穷尽努力,想使得排序和查找能够更加快速.本篇文章用Python实现十大排序算法. 很多人学习python,不知 ...

  5. 这或许是东半球分析十大排序算法最好的一篇文章

    作者 | 不该相遇在秋天 转载自五分钟学算法(ID:CXYxiaowu) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强 ...

  6. 十大排序算法(C++)

    十大排序算法Sorting algorithm(C++) 百度百科:   所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列 ...

  7. DSA之十大排序算法第六种:Quick Sort

    快速排序 2019年8月23日17:45:21 之前我们已经分析过 冒泡排序,我建议:当你在看这篇博客的时候,请先回顾 冒泡排序:详见DSA之十大排序算法第一种:Bubble sort 文章目录 一次 ...

  8. 算法基础-十大排序算法及其优化(文末有抽奖福利哦)

    算法基础-十大排序算法及其优化 算法基础-十大排序算法及其优化 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kw1LA5Q4-1607527572080)(/uplo ...

  9. 「干货总结」程序员必知必会的十大排序算法

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 绪论 身 ...

最新文章

  1. 数组公式基本功修炼之深入使用
  2. 汇编 过程 创建并测试 proc endp call ret uses
  3. 压测场景下的 TIME_WAIT 处理
  4. 快手直播平台演进之路
  5. .NET开发者必须学习.NET Core
  6. java用数组实现随机不重复抽奖
  7. 关于屏幕分辨率的一些操作
  8. C++ 里利用 std::ios::sync_with_stdio(false) 解决TLE问题
  9. 【Unity3d】【项目学习心得】从资源服务器下载资源(二)
  10. ef 子表和父表不同时保存_canon粉不懂镜头参数?我只能嘲笑你
  11. SPSS输出结果统计表与统计图的专业性编辑及三线表定制格式
  12. 三本毕业,三年嵌入式软件的心路历程
  13. 纪录片《Code Rush》
  14. ssh外网访问内网服务器
  15. android关闭听筒模式,Android开发【06-29视频贴】切换听筒模式部分手机失效,怎么解决?...
  16. 现代 React Web 开发实战——kanban实现卡片拖拽
  17. STM32F407学习笔记——MG90S舵机模块(基本控制)
  18. 文本检测之DBNet,DBNet++
  19. ku115上实现adc12dj3200 配置,jesd204b接口,单通道采集模式
  20. 读取qq聊天记录文件(诺基亚塞班S60v3平台)

热门文章

  1. DataGrid 中間隔色的實現
  2. getopt实现传参自动识别
  3. linux命令 - free -m
  4. ES6 new syntax of Default Function Parameters
  5. junit4 javaee 5.0 jpa SSH 单元测试问题集锦
  6. Android 开机自动启动服务
  7. linux 命令提示符 时间,在LINUX的命令提示符及CMD命令提示符中显示时间
  8. maven版本高于idea
  9. Mysql商品和图片表_【mysql】数据库设计模式:多个图片怎么和商品关联
  10. python网络编程证书_《Python网络编程基础》笔记