排序算法--(冒泡排序,插入排序,选择排序,归并排序,快速排序,桶排序,计数排序,基数排序)

一.时间复杂度分析

- **时间复杂度**:对排序数据的总的操作次数。反应当n变化时,操作次数呈现什么规律
- **空间复杂度**:算法在计算机内执行时所需要的存储空间的容量,它也是数据规模n的函数。

1.例题:

有一个字符串数组,将数组中的每一个字符串按照字母序排序,之后再将整个字符串数组按照字典序排序,时间复杂度多少?

假设最长字符串长度为s,有n个字符串,则每个字符串按照字母序排序时间复杂度为:O(n*slogs)

整个字符串数组按照字典序排序时间复杂度为:O(s*nlogn),所以总的时间复杂度为:O(n*slogs+s*nlogn)

各种排序算法复杂度:

二.各种排序算法

1.冒泡排序:

**复杂度分析:**

- 时间复杂度:若给定的数组刚好是排好序的数组,采用改进后的冒泡排序算法,只需循环一次就行了,此时是最优时间复杂度:O(n),若给定的是倒序,此时是最差时间复杂度:O(n^2) ,因此综合平均时间复杂度为:O(n^2)
- 空间复杂度:因为每次只需开辟一个temp的空间,因此空间复杂度是:O(1),是一个原地排序算法,等于的话不做交换,故是一个稳定的排序算法。

步骤:

1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
3. 针对所有的元素重复以上的步骤,除了最后一个;
4. 重复步骤1~3,直到排序完成。

代码:

"""
冒泡排序:从小到大
"""
def BubbleSort(array):lengths = len(array)for i in range(lengths-1):for j in range(lengths-1-i):if array[j] > array[j+1]:array[j+1], array[j] = array[j], array[j+1]return arrayif __name__ == '__main__':# array=[5,3,5,8,1,-4,56,87]# print(array)# QuickSort(array,0,len(array)-1)# print(array)array = [5, 3, 5, 8, 1, -4, 56, 87]print("Original array: ", array)array = BubbleSort(array)print("BubbleSort: ", array)

c++实现:

//
// Created by fzh on 2021/4/29.
//
#include <iostream>
#include <string>
using namespace std;
void bubbleSort(int* p, int length){for(int i = 0; i < length - 1; i++){for(int j = 0; j<length - i - 1; j++){if(p[j] > p[j + 1]){
//                cout<<"==arr[j]:"<<arr[j]<<endl;int temp = p[j];p[j] = p[j + 1];p[j + 1] = temp;}}}
}
int main() {int arr[10] = {2,2,3,5,19,6,7,8,9,10};int length = sizeof(arr)/sizeof(arr[0]);cout<<"==length:"<<length<<endl;bubbleSort(arr, length);for(int i=0; i<10; i++){cout<< "==arr[i]:" <<arr[i] <<endl;}
}

2.插入排序

将未排序元素一个个插入到已排序列表中。对于未排序元素,在已排序序列中从后向前扫描,找到相应位置把它插进去;在从后向前扫描过程中,需要反复把已排序元素逐步向后挪,为新元素提供插入空间。空间复杂度是O(1),也就是一个原地排序算法,稳定的排序算法,平均时间复杂度O(n2),相比冒泡排序其更受欢迎,主要冒泡排序的数据交换要比插入排序复杂,冒泡排序需要三个赋值操作,而插入排序只需要一个。

"""
插入排序:从小到大
"""
def InsertionnSort(array):lengths = len(array)# 从索引位置1开始for i in range(1, lengths):currentValue = array[i]  # 当前索引对应的元素数值preIndex = i - 1  # 前一个索引位置# 循环条件: 前一个索引对应元素值大于当前值,前一个索引值大于等于0while array[preIndex] > currentValue and preIndex >= 0:array[preIndex + 1] = array[preIndex]  # 前一个索引对应元素值赋值给当前值preIndex -= 1  # 前一个索引位置-1# preIndex+1,实现元素交换array[preIndex + 1] = currentValuereturn arrayarray = [1, 0, 8, -2, 3, 6, 9]
print("Original array={}".format(array))
array = InsertionnSort(array)
print("InsertionSort={}".format(array))
def insert_sort():a = [9, 8, 3, -3, -7, 1, -5]for i in range(1,len(a)):# value = a[i]for j in range(0,i-1):if a[j]>a[i]:a[j],a[i]=a[i],a[j]print(a)

3.选择排序

说明:首先在未排序序列中找到最小(大)元素,与起始位置元素进行交换,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后在交换。以此类推,直到所有元素均排序完毕。空间复杂度是O(1),是原地排序算法,平均时间复杂度是O(n2),是不稳定的排序算法,因为每次都要找未排序的最小值交换,

比如 5,8,5,2,9 这样一组数据,使用选择排序算法来排序,2要跟第一个5发生交换,那么这两个5的顺序就发生了变化,

 

def SelectionSort(arr):for i in range(len(arr)-1):minIndex=ifor j in range(i+1,len(arr)):if arr[j]<arr[minIndex]:minIndex=jif i!=minIndex:arr[i],arr[minIndex]=arr[minIndex],arr[i]return arr
arr=[-1,-3,-6,3,4,0,2]
print(arr)
arr=SelectionSort(arr)
print(arr)

4.归并排序

归并排序和快速排序,时间复杂度为O(nlogn),更适合大规模的数据排序,采用了分治的思想,由于借用temp数组,故空间复杂度为O(n),,是一个稳定的排序算法。

写法1:

def Merge(q, r):left, right = 0, 0result = []while left < len(q) and right < len(r):# 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置if q[left] < r[right]:result.append(q[left])left += 1else:result.append(r[right])right += 1result += q[left:]    # 若最后left列表剩余,则将其剩余部分加入到result后面result += r[right:]   # 若最后right列表剩余,则将其剩余部分加入到result后面return resultdef Merge_Sort(L):if len(L) <= 1:return Lmid = len(L) // 2         # 这里的//是python3中除以后取整的用法,大家不要以为我打错了~q = Merge_Sort(L[:mid])r = Merge_Sort(L[mid:])return Merge(q, r)a=[1,2,9,0,8,2,3]
b=Merge_Sort(a)
print(b)

写法2:

class Solution:def mergeSort(self, nums, start, end):if start >= end:returnmid = start + (end - start) // 2self.mergeSort(nums, start, mid)self.mergeSort(nums, mid + 1, end)self.merge(nums, start, mid, end)def merge(self, nums, start, mid, end):i, j, temp = start, mid + 1, []while i <= mid and j <= end:if nums[i] <= nums[j]:temp.append(nums[i])i += 1else:self.cnt += mid - i + 1temp.append(nums[j])j += 1while i <= mid:temp.append(nums[i])i += 1while j <= end:temp.append(nums[j])j += 1for i in range(len(temp)):nums[start + i] = temp[i]print('==nums:', nums)def reversePairs(self, nums):self.cnt = 0self.mergeSort(nums, 0, len(nums) - 1)print('==after nums:', nums)return self.cntnums = [7,5,6,4]
sol = Solution()
sol.reversePairs(nums)
print(sol.cnt)

k路归并排序:

给出K个有序的数组现在将其归并成一个有序数组怎么做最快。

def Merge(q, r):left, right = 0, 0result = []while left < len(q) and right < len(r):# 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置if q[left] < r[right]:result.append(q[left])left += 1else:result.append(r[right])right += 1result += q[left:]  # 若最后left列表剩余,则将其剩余部分加入到result后面result += r[right:]  # 若最后right列表剩余,则将其剩余部分加入到result后面return resultdef Merge_Sort(L):if len(L) <= 1:return L[0]mid = len(L) // 2q = Merge_Sort(L[:mid])r = Merge_Sort(L[mid:])print('==q==:', q)print('==r==:', r)return Merge(q, r)# a = [1, 2, 9, 0, 8, 2, 3]
a = [[1, 2],[0, 3],[-4, 8]]
b = Merge_Sort(a)
print('==b:', b)

5.快速排序

思想:通过一趟排序将待排列表分成独立的两部分,其中一部分的所有元素均比另一部分的元素小,则分别对这两部分继续重复进行此操作,以达到整个序列有序。

步骤:

使用分治法把一个串分为两个子串,具体算法描述如下:

1,从数列中挑出一个元素,称为'基准'(privot),本文将第一个选为基准;

2,比基准数小的所有元素放在基准前面,比基准数大的所有元素放在基准后面,这样完成了分区操作;

3,递归地把小于基准值元素的子数列和大于基准值元素的子数列按上述操作进行排序,递归结束条件序列的大小为0或1。

根据分治,递归的处理思想,利用递归排序下标从p到q-1之间的数据,和下标从q+1到r之间的数据,直至区间缩小为1,说明所有的数据都有序了,跟归并排序不同的是,要做成原地排序算法,不借用temp,空间复杂度为O(1),时间复杂度为O(nlogn)。由于涉及到选择基准,倘若基准是两个相同的数,经过分区处理后,顺序可能发生变化,故是不稳定的算法。

流程:

代码:

def QuickSort(array,start,end):length=len(array)i=startj=endif i>=j:returnprivot=array[i]while i<j:#从右往左while i<j and privot<=array[j]:j-=1array[i]=array[j]# print(array)# 从左往右while i < j and privot >= array[i]:i+= 1array[j] = array[i]# print(array)array[i]=privot# print(array)#QuickSort(array,start,i-1)QuickSort(array, i+1, end)
if __name__ == '__main__':array=[5,3,5,8,1,-4,56,87]print(array)QuickSort(array,0,len(array)-1)print(array)

更快的方式:

#选择中间的数作为基准
def quicksort(arr):if len(arr) <= 1:return arrpivot = arr[len(arr) // 2]left = [x for x in arr if x < pivot]print('left=',left)middle = [x for x in arr if x == pivot]print('middle=', middle)right = [x for x in arr if x > pivot]print('right=', right)return quicksort(left) + middle + quicksort(right)
if __name__ == '__main__':print(quicksort([9,8,7,6,5,43,2]))

6.桶排序

桶排序,将要排序的数据分到几个有序的桶里,每个桶里的数据单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。桶排序的时间复杂度为什么是 O(n) 呢?排序数据有n个,均匀划分到m个桶内,每个桶就有k=n/m个元素,每个桶使用快速排序,时间复杂度为O(k*logk)。m个桶排序时复杂度就是O(m*k*logk),故整个桶排序时间复杂度就是O(n*(log(n/m))),m足够大时,log(n/m)是一个很小的值,故时间复杂度接近O(n)。极端情况下,分到一个桶里,就变为O(n*logn),其适合外部排序,也就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。其是一个稳定的排序算法。

7.计数排序

计数排序可以看成是桶排序的一种特设请情况,考生的满分是 900 分,最小是 0 分,这个数据的范围很小,可以分成901个桶,将50万考生划分到901个桶,桶内的数据是相同分数的考生,只需要依次扫描每个桶,将桶内的考生依次输出到一个数组中,即实现排序,也就是计数排序,其只适合于数据范围不大的场景,如果数据范围k比排序数据n大很多,就不是和计数排序了,而且只适合给非负整数排序,若有负数,需要转换成正数,归一化。其是一个稳定的排序算法,时间复杂度O(n)

8.基数排序

基数排序,假设有10万个手机号码,希望将这10万个手机号码按下到大排序,时间复杂度O(n),基数排序对要排序的数据是有要求的,需要可以分割出独立的‘位’来比较,而且具有递进的关系。其是一个稳定的排序算法。

下面用字母来代替。

总结:Glibc的qsort()函数会优先使用归并排序,对于1k,2k左右的数据,完全可以用空间換时间,因为其空间复杂度是O(n),时间复杂度是O(nlogn)。
对于小数量数据的排序,O(n2)的排序算法并不一定比O(nlogn)排序算法执行时间长,对于小数据的排序,选择简单,
不需要递归的插入排序算法,递归过深容易导致堆栈溢出。

数据量较大的情况就用快速排序,分区点的选择可以用三数取中法和随机法
1,三数取中法,从区间的首,尾,中间分别取出一个数,然后比对大小,取这三个数的中间值作为分区点,如果排序的数组很大,可能就要用多个数来取中间值。
2,随机法,每次从要排序的区间,随机选择一个元素作为分区点,从概率的角度讲不会出现每个分区点都会选的很差的情况。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

肠里细菌“肚里蛔虫”:肠脑研究缘何越来越热

来源&#xff1a;科学网最懂你大脑的&#xff0c;可能不是“肚子里的蛔虫”&#xff0c;而是肠子里的细菌——肠道菌群对神经系统、心理和行为方面的影响正成为一个新兴热点领域。在日前举办的美国神经科学学会年会上&#xff0c;一张海报上的大脑切片显微镜图像显示&#xff0…

SVM原理与实战

先看线性可分问题。对于线性可分&#xff0c;其实感知机就可以解决。但是感知机只是找到一个超平面将数据分开&#xff0c;而这样的超平面可能是平行的无限多个&#xff0c;我们需要在这其中找到最优的一个。怎么衡量一个超平面是不是最优的呢&#xff0c;直观上讲&#xff0c;…

2014-01-01

一:HyperlinkButton点击后打开新窗口的方法 1,直接在界面中写这段代码就可以了: <HyperlinkButton NavigateUri"http://www.cnblogs.com/wsdj-ITtech/" Content"Click Me" TargetName"_blank" FontSize"28" Height"50"…

李飞飞高徒:斯坦福如何打造基于视觉的智能医院?

作者&#xff1a;Albert Haque、Michelle Guo来源&#xff1a;机器之心自 2009 年担任斯坦福人工智能实验室和视觉实验室的负责人&#xff0c;李飞飞在推动计算机视觉方面研究的同时&#xff0c;还密切关注 AI 医疗的发展。昨日&#xff0c;李飞飞离任斯坦福 AI 实验室负责人一…

tensorflow知识点

一.bazel编译tensorflow注意版本号: 在/tensorflow/tensorflow/configure.py 查看bazel版本号 https://github.com/tensorflow/tensorflow https://github.com/bazelbuild/bazel/releases?after0.26.1 https://tensorflow.google.cn/ 二&#xff0c;基础知识点 1.打印出…

eclipse中如何导入jar包

如图&#xff0c;首先右键点击项目&#xff0c;选择最下面的properties&#xff0c; 然后进去之后点击java build path&#xff0c;右边会出来4个选项卡&#xff0c;选择libraries&#xff0c; 这时候最右边会有多个选项&#xff0c;第一个add jars是添加项目文件中的jar包&…

线性-LR-softmax傻傻分不清楚

softmax 对于分类网络&#xff0c;最后一层往往是全连接层&#xff0c;如果是N分类&#xff0c;那么最终的全连接层有N个结点。很显然&#xff0c;每个节点对应一个类&#xff0c;该节点的权重越大&#xff0c;说明网络越倾向于认为输入样本属于该类。这其实就是Softmax的思想…

一图看懂国外智能网联汽车传感器产业发展!

来源&#xff1a;赛迪智库编辑&#xff1a;煜 佳未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#…

深度学习中的信息论——交叉熵

信息量 可以说就信息量是在将信息量化。首先信息的相对多少是有切实体会的&#xff0c;有的人一句话能包含很多信息&#xff0c;有的人说了等于没说。我们还可以直观地感觉到信息的多少和概率是有关的&#xff0c;概率大的信息也相对低一些。为了量化信息&#xff0c;一个做法…

传统手工特征--opencv

一&#xff0c;颜色特征&#xff1a; 简单点来说就是将一幅图上的各个像素点颜色统计出来&#xff0c;适用颜色空间&#xff1a;RGB&#xff0c;HSV等颜色空间&#xff0c; 具体操作&#xff1a;量化颜色空间&#xff0c;每个单元&#xff08;bin&#xff09;由单元中心代表&…

特写李飞飞:她激励了人工智能的发展,更要给人工智能赋予人的价值

文 | MrBear 编辑 | 杨晓凡来源&#xff1a;雷锋网摘要&#xff1a;李飞飞无疑是人工智能界最响亮的名字之一。她既对机器学习领域的发展做出了杰出的贡献&#xff0c;也是普通大众眼中温和的人工智能技术宣扬者&#xff0c;还是谷歌这一科技巨头的人工智能技术领导人之一。WI…

Chap-4 Section 4.2.4 指令修正方式

对于X86平台下的ELF文件的重定位入口所修正的指令寻址方式只有两种&#xff1a;绝对近址32寻址和相对近址32寻址。 这两种指令修正方式每个被修正的位置的长度都为32位&#xff0c;即4个字节&#xff0c;而且都是近址寻址&#xff0c;不用考虑Intel的段间远址寻址。r_info成员的…

没见过女人的小和尚——SVDD

是的&#xff0c;即便是出生在山上的小和尚&#xff0c;从来没有下过山&#xff0c;没有见过女人&#xff0c;但是一旦有女施主上山&#xff0c;小和尚依然可以轻松地区分出眼前的人是如此不同。 传统的SVM是寻找一个超平面&#xff0c;而SVDD寻找的超平面更进一步&#xff0c…

解读GAN及其 2016 年度进展

作者&#xff1a;程程 链接&#xff1a;https://zhuanlan.zhihu.com/p/25000523 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 GAN&#xff0c;全称为Generative Adversarial Nets&#xff0c;直译为生成式对抗网络…

全国首套中小学生人工智能教材在沪亮相

来源&#xff1a;网络大数据中小学 AI 教材正式亮相11 月 18 日&#xff0c;优必选与华东师范大学出版社共同发布了《AI 上未来智造者——中小学人工智能精品课程系列丛书》&#xff08;以下简称“AI 上未来智造者”丛书&#xff09;。据了解&#xff0c;该丛书根据教育部“义务…

numpy基础知识点

1. np.squeeze 一,np.squeeze """ np.squeeze 删除单维度的条 对多维度无效 """ import numpy as np anp.array([[1,2],[3,4],[4,5]]) print(a) print(a.shape) bnp.squeeze(a) print(b) ca.reshape(1,6,1) print(c) print(np.squeeze(c)) pri…

从智能交通到智能能源:智慧城市在7个方面的应用实践

来源&#xff1a;资本实验室目前&#xff0c;智慧城市已经成为全球众多城市未来规划和设计的方向&#xff0c;并致力于通过各种新技术的应用来改善城市居民的工作与生活。但什么样的技术应用能够推动智慧城市的建设&#xff1f;如何让新技术在智慧城市中的应用效率最大化&#…

别以为if slse很简单——决策树

怎么分——熵与Gini指数 熵&#xff0c;表示信息量的期望&#xff0c;含义是混乱程度&#xff0c;也是对随机变量编码所需的最小比特数。请参考之前的文章。 信息增益建立在熵之上&#xff0c;是选择某特征之后熵减少的多少&#xff08;熵减少即信息增加&#xff09;&#xf…

tensorflow实现回归

直线拟合&#xff1a;yw*xb """ 回归:直线拟合 """ import tensorflow as tf import numpy as np import matplotlib.pyplot as plt x_datanp.random.rand(100) y_datax_data*51Wtf.Variable(0.) btf.Variable(0.) y_predW*x_databxtf.placehol…

微软亚研院20周年独家撰文:数据智能的现在与未来

文&#xff1a;微软亚洲研究院软件分析组来源&#xff1a;雷锋网摘要&#xff1a;今年是微软亚洲研究院&#xff08;MSRA&#xff09;20周年&#xff0c;站在这个大节点上&#xff0c;MSRA副院长张冬梅以及她的团队写了这篇有关数据智能的文章&#xff0c;对该领域的发展和未来…