近期总结。
一.冒泡排序(Bubble Sort)
冒泡排序,是一种简单的排序算法,实现方式可以简单理解为依次比较两个相邻元素,根据由大到小或者由小到大的规则,进行交换。由冒泡的名称也可联想一二,这种排序方式会使较大或者较小的元素慢慢浮到顶端。
具体运作如下(升序为例):
1.一个序列,从第一位元素开始,比较第一第二位,若第一位值大于第二位(不符合升序规则),将两个元素交换位置;否则继续比较第二和第三位。这样两两比较直到没有相邻元素交换。
2.这样一轮比较下来,可以保证的是最后一位是最大的。所以剔除最后一位,再次重复第一步操作。
3.每一轮后去除最后一位,对越来越少的剩余元素重复上述步骤,直到没有数字进行比较。
冒泡排序动态演示:
python的实现:
def maopao(arr):
# 外循环每次剔除最后一位,逐渐减小,共循环n-1次
for i in range(len(arr)-1,0,-1):
# 内循环进行除最后一位的两两比较
for j in range(i):
# 不符合升序规则,进行交换
if arr[j] > arr[j+1]:
arr[j],arr[j+1] = arr[j+1],arr[j]
时间复杂度
1.最优时间复杂度:O(n) --遍历一次未发现可交换元素
2.最坏时间复杂度:O(n2)
3.稳定性:稳定
二.选择排序(Selection sort)
选择排序,是一种比较直观的排序方法。实现方法可以简单理解为把最大或者最小的元素选出来,通过交换放在前排。个人理解起来感觉和冒泡有点像,选取完后放在前排,然后在剩下的元素里再选取最大或最小接着放在前排,可以结合冒泡冒到顶端的思想,在这方面有点异曲同工。在排序时核心还是交换元素。
具体运作如下最(升序为例):
1.首先假定第一个元素为最小,来遍历之后的元素,如果发现有比第一个元素还小的,那么交换这两个元素。
2.这样排下来,可以保证的是第一个元素为最小元素。接下来剔除第一位,从第二位重复上述操作。
3.每次剔除最前一位,依次循环下来,得出排序。
选择排序动态演示
python的实现:
def xuanze(arr):
# 循环到倒数第二位,即 共循环n-1次
for i in range(len(arr)-1):
# 假定最小元素索引为当前开始元素
min_ind = i
# 在当前元素之后进行遍历,查找最小元素索引
for j in range(i+1,len(arr)):
if arr[j] < arr[min_ind]:
min_ind = j
#查找完毕,进行交换
arr[i],arr[min_ind] = arr[min_ind],arr[i]
时间复杂度
1.最优时间复杂度:O(n2)
2.最坏时间复杂度:O(n2)
3.稳定性:不稳定(考虑升序每次选择最大的情况)
三.插入排序(Insertion Sort)
插入排序,也是比较直观的一种排序方法。从名称上理解,插入,举例来说,当有一个新数据要插入原有序列,假定为从小到大,形成新的有序列表,我们采用从后往前的方法比较,当发现某个元素比新元素大,我们会将该元素往后移一位,这样从后往前依次比较,发现某个元素比新元素小时,停止移位,将新元素插入,最终完成插入。该方法首先要基于有一个有序列表,所以从单一元素开始排起,逐步至排完。
具体运作如下最(升序为例):
1.从首位开始,插入第二位元素,若该元素大于首位元素,则不动;不然交换位置。接着第三个元素,从第二个元素开始比较,若第二个元素大于第三个元素,则移位,再同理同第一个元素相比。
2.这样依次比较,移位,插入,直到比完。
插入排序动态演示
python实现
def charu(arr):
# 外循环共n-1次
for i in range(1,len(arr)):
# 内循环,从当前i,从后往前开始移位插入
for j in range(i,0,-1):
# 若后位元素小于前位元素,则交换前移
if arr[j] < arr[j-1]:
arr[j],arr[j-1] = arr[j-1],arr[j]
时间复杂度
1.最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
2.最坏时间复杂度:O(n2)
3.稳定性:稳定
四.快速排序(Quicksort)
快速排序,相较前三种,感觉有点不一样。引用百度百科释义“通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。”
个人理解,选一个中间数,把比该元素大的分一个列表,比该元素小的分一个列表,引用递归思想,再对分出来的两个列表同理,递归直到分出来的列表只有一个元素。
快速排序图示
这个图示,比较清楚的展示了快速排序的过程,也提供了一套实现思路,主要是通过设置左右两个游标,进行易位分区,当初看到动手就觉得有点复杂。后来看过某位大神写的,非常优雅厉害,理解也很畅通。这里分别尝试两套思路实现。
python常规实现
def kuaisu(arr,start,end):
# 递归退出条件
if start>=end:
return
# 假定中间值
mid = arr[start]
# 设置左右游标
left = start
right = end
#游标未重合
while left < right:
# 右分区为大区,如果比中间值大,游标移动
if left < right and arr[right]>=mid:
right-=1
# 比中间值小,将该值易位到左游标
arr[left] =arr[right]
# 左分区为小区,如果比中间值小,游标移动
if left <right and arr[left]<mid:
left+=1
# 比中间值大,将该值易位到右游标
arr[right] = arr[left]
# 此时左右游标重合,将中间值放上
arr[left] = mid
# 分别对两边进行递归
kuaisu(arr,start,left-1)
kuaisu(arr,left+1,end)
python优雅实现
def quicksort(arr):
# 递归退出条件,当arr为1时不需要再排序
if len(arr)<2:
return arr
else:
mid = arr[0]
# 剩余元素大小分区
min_l = [i for i in arr[1:] if i <=mid]
max_l = [i for i in arr[1:] if i >mid]
# 递归大小分区
return quicksort(min_l)+[mid]+quicksort(max_l)
时间复杂度
1.最优时间复杂度:O(nlogn)
2.最坏时间复杂度:O(n2)
3.稳定性:不稳定
总的来说,冒泡,选择,插入比较好理解,共同点是通过交换元素的方法,完成某种特定的排序。快速排序说是冒泡排序的一种改进,刚接触,理解还不是那么深刻,感觉还需多磨。
写在最后,这几天研究数据结构和算法,虽然还是有点懵,但是慢慢磨下来,还是感觉不错 ,每天磨一磨,理解也越来越深,果然还是多练!