排序算法Python实现合辑

基本排序算法:

1. 选择排序(seletionSort):

搜索整个列表,找到最小项的位置,如果该位置不是列表的第一个位置,算法就交换这两个位置的项。然后,算法回到第二个位置,并重复这个过程。

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

《数据结构:Python语言描述》:

def swap(lyst, i, j):
    '''Exchanges the items at positions i and j'''
    temp = lyst[i]
    lyst[i] = lyst[j]
    lyst[j] =temp

def selectionSort(Lyst):
    i = 0
    while i < len(Lyst)-1:
        minIndex = i
        j = i + 1
        while j < len(Lyst):
            if Lyst[j] < Lyst[minIndex]:
                minIndex = j
            j += 1
        if minIndex != i:
            swap(Lyst, minIndex, i)
        i += 1
    return Lyst

我自己根据书上改的:

def selectionSort(Lyst):
    i = 0
    while i < len(Lyst)-1:
        j = i + 1
        while j < len(Lyst):
            if Lyst[j] < Lyst[i]:
                Lyst[i],Lyst[j] = Lyst[j],Lyst[i] 
            j += 1
        i += 1
    return Lyst

for 循环方法:

def selectionSort(list):
    length=len(list)
    for i in range(length):
        for j in range(i+1,length):
            if list[j] < list[i]:
                list[j],list[i]=list[i],list[j]
    return list
Lyst = [2,1,4,7,3,8,4,9,1,3]
print(selectionSort(Lyst))
[1, 1, 2, 3, 3, 4, 4, 7, 8, 9]

2. 冒泡排序(bubbleSort):

从列表的开头处开始,比较一对数据项,知道移动到列表的末尾,这样每趟排序会把最大的数字扔到最后面。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。

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

《数据结构:Python语言描述》:

def bubbleSort(lyst):
    n = len(lyst)
    while n > 1:
        i = 1
        while i < n:
            if lyst[i] < lyst[i - 1]:
                swap(lyst, i , i-1)
            i += 1
        n -= 1
    return lyst

for 循环方法:

def bubbleSort(lyst):
    # 外层循环控制从头走到尾的次数
    for j in range(len(lyst) - 1):
        # 内层循环控制走一次的过程
        for i in range(0, len(lyst) - j - 1):
            # 如果前一个元素大于后一个元素,则交换两个元素(升序)
            if lyst[i] > lyst[i + 1]:
                lyst[i], lyst[i + 1] = lyst[i + 1], lyst[i]
	return lyst

针对冒泡排序进行一个小的调整,将其最好情况下的性能提高到线性阶,但平均复杂的仍是 O ( n 2 ) O(n^2)

def bubbleSortWithTweak(lyst):
    n = len(lyst)
    while n > 1:
        i = 1
        while i < n:
            if lyst[i] < lyst[i - 1]:
                swap(lyst, i , i-1)
                swapped = True
            i += 1
        if not swapped: return
        n -= 1
    return lyst

用递归实现冒泡?

3. 插入排序(insertionSort):

“一趟一个“地将待排序记录插入到已经排好序的部分记录的适当位置中,使其成为一个新的有序序列,直到所有待排序记录全部插入完毕。在第i轮通过列表的时候(其中i的范围从1到n-1),第i个项应该插入到列表的前i个项之中的正确位置。在第i轮之后,前i个项应该是排序好的。

列表中排好序的项越多,插入排序的效果越好。

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

《数据结构:Python语言描述》:

def insertSort(lyst):
    i = 1
    while i < len(lyst):
        itemToInsert = lyst[i]
        j = i - 1                
        while j >= 0:
            if itemToInsert < lyst[j]:
                lyst[j + 1] = lyst[j]
                j -= 1
            else:
                break
        lyst[j + 1] = itemToInsert
        i += 1
    return lyst

[2,4,3,1]>[2,4,3,1]>[2,3,4,1]>[2,3,1,4]>[2,1,3,4]>[1,2,3,4]

更快的排序算法

采用分而治之(divide-and-conquer)的策略。将列表分解为更小的子列表,随后,这些子列表递归的排序。算法复杂度: O ( n l o g n ) O(nlogn)

1.1 快速排序(quickSort)

随意选择一个数字(可选中点)作为基准(pivot)分割列表,比基准数字大的放在右,比基准数字小的放在左。对于子列表,递归地重复应用该过程。直到子列表的长度最大为1。

《数据结构:Python语言描述》:

def swap(lyst, i, j):
    '''Exchanges the items at positions i and j'''
    temp = lyst[i]
    lyst[i] = lyst[j]
    lyst[j] =temp

def quickSort(lyst):
    quickSortHelper(lyst, 0, len(lyst)-1)

def quickSortHelper(lyst, left, right):
    if left < right:
        print(lyst)
        pivotLocation = partition(lyst, left, right)
        print(lyst[pivotLocation])
        quickSortHelper(lyst, left, pivotLocation - 1) 
        quickSortHelper(lyst, pivotLocation + 1, right)
            
def partition(lyst, left, right):
    middle = (left + right) // 2
    pivot = lyst[middle]
    lyst[middle] = lyst[right]
    lyst[right] = pivot
    boundary = left
    for index in range(left, right):
        if lyst[index] < pivot:
            swap(lyst, index, boundary)
            boundary += 1
            print(lyst)
    swap(lyst, right, boundary)
    return boundary

Lyst = [12,19,17,18,14,11,15,13,16]
quickSort(Lyst)
print(Lyst)

快速排序递归分析:

1.遍历所有元素,使比基准小的在基准左,比基准大的在基准右,故先将基准换到最右侧。

2.然后从左到右遍历,找到比基准小的元素,从第一个位置开始依次互换。

3.如12先跟自己互换,然后11和19互换,然后13和17互换,最后基准14和18互换。

4.递归对左边子列表重复操作:基准11换到末端即11和13互换,然后11和12互换。

5.左边已不可再分,开始分右边子列表。首先基准15换到末端即15和18互换,然后15

[12, 19, 17, 18, 14, 11, 15, 13, 16]
[12, 19, 17, 18, 16, 11, 15, 13, 14]
[12, 11, 17, 18, 16, 19, 15, 13, 14]
[12, 11, 13, 18, 16, 19, 15, 17, 14]
14
[12, 11, 13, 14, 16, 19, 15, 17, 18]
11
[11, 13, 12, 14, 16, 19, 15, 17, 18]
[11, 12, 13, 14, 16, 19, 15, 17, 18]
13
[11, 12, 13, 14, 16, 19, 15, 17, 18]
15
[11, 12, 13, 14, 15, 19, 18, 17, 16]
[11, 12, 13, 14, 15, 16, 19, 17, 18]
[11, 12, 13, 14, 15, 16, 17, 19, 18]
18
[11, 12, 13, 14, 15, 16, 17, 18, 19]
16
[11, 12, 13, 14, 15, 16, 17, 18, 19]

1.2 算法导论 快速排序:

# quickSort, quickSortHelper 同上

def partition(lyst, left, right):
    x = lyst[right]
    i = left- 1
    for j in range(left, right):
        if lyst[j] <= x:
            i += 1
            lyst[i], lyst[j] = lyst[j], lyst[i]
            print(lyst)
    lyst[i + 1], lyst[right] = lyst[right], lyst[i+1]
    return i + 1

Lyst = [12,19,17,18,14,11,15,13,16]
quickSort(Lyst)
print(Lyst)
[12, 19, 17, 18, 14, 11, 15, 13, 16]
[12, 19, 17, 18, 14, 11, 15, 13, 16]
[12, 14, 17, 18, 19, 11, 15, 13, 16]
[12, 14, 11, 18, 19, 17, 15, 13, 16]
[12, 14, 11, 15, 19, 17, 18, 13, 16]
[12, 14, 11, 15, 13, 17, 18, 19, 16]
16
[12, 14, 11, 15, 13, 16, 18, 19, 17]
[12, 14, 11, 15, 13, 16, 18, 19, 17]
[12, 11, 14, 15, 13, 16, 18, 19, 17]
13
[12, 11, 13, 15, 14, 16, 18, 19, 17]
11
[11, 12, 13, 15, 14, 16, 18, 19, 17]
14
[11, 12, 13, 14, 15, 16, 18, 19, 17]
17
[11, 12, 13, 14, 15, 16, 17, 19, 18]
18
[11, 12, 13, 14, 15, 16, 17, 18, 19]

2.1 归并排序(mergeSort)

创建在归并操作上的一种有效的排序算法,效率为 O ( n l o g n ) O(n log n) 。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

merge 函数将两个排好序的子列表合并到一个大的排好序的子列表中,第1个子列表在low和middle之间,第2个子列表在middle+1到high之间。这个过程包含3个步骤:
1.将索引指针设置为每个子列表的第一项,分别是low和middle+1
2.从每个子列表的第一项开始,重复地比较各项。将较小的项从其子列表中复制到复制缓存中,并且继续处理子列表中的下一项。重复这个过程,直到两个子列表中的所有的项都已经复制过了。如果先到达了其中的一个子列表的末尾,通过从另一个子列表复制剩余的项,从而结束这个步骤。
3.将copyBuffer中的low和high之间的部分,复制回lyst中对应的位置。

《数据结构:Python语言描述》:

import sys
sys.path.append(r'C:\Users\Qiuyi\eclipse-workspace\DataStructure3.0\programs\Ch_4_Student_Files')

from arrays import Array

def mergeSort(lyst):
    copyBuffer = Array(len(lyst))
    mergeSortHelper(lyst, copyBuffer, 0, len(lyst)-1)
    
def mergeSortHelper(lyst, copyBuffer, low, high):
    if low < high:
        middle = (low + high) // 2
        mergeSortHelper(lyst, copyBuffer, low, middle)
        mergeSortHelper(lyst, copyBuffer, middle + 1, high)
        merge(lyst, copyBuffer, low, middle, high)
        
def merge(lyst, copyBuffer, low, middle, high):
    i1 = low
    i2 = middle + 1
    
    for i in range(low, high + 1):
        if i1 > middle:
            copyBuffer[i] = lyst[i2]
            i2 += 1
        elif i2 > high:
            copyBuffer[i] = lyst[i1]
            i1 += 1
        elif lyst[i1] < lyst[i2]:
            copyBuffer[i] = lyst[i1]
            i1 += 1
        else:
            copyBuffer[i] = lyst[i2]
            i2 += 1
    for i in range(low, high + 1):
        lyst[i] = copyBuffer[i]
        
Lyst = [12,19,17,18,14,11,15,13,16]
mergeSort(Lyst)
print(Lyst)
"""
File: arrays.py

An Array is a restricted list whose clients can use
only [], len, iter, and str.

To instantiate, use

<variable> = array(<capacity>, <optional fill value>)

The fill value is None by default.
"""

class Array(object):
    """Represents an array."""

    def __init__(self, capacity, fillValue = None):
        """Capacity is the static size of the array.
        fillValue is placed at each position."""
        self._items = list()
        for count in range(capacity):
            self._items.append(fillValue)

    def __len__(self):
        """-> The capacity of the array."""
        return len(self._items)

    def __str__(self):
        """-> The string representation of the array."""
        return str(self._items)

    def __iter__(self):
        """Supports iteration over a view of an array."""
        return iter(self._items)

    def __getitem__(self, index):
        """Subscript operator for access at index."""
        return self._items[index]

    def __setitem__(self, index, newItem):
        """Subscript operator for replacement at index."""
        self._items[index] = newItem

2.2 简书归并排序算法:

def mergesort(seq):
    """归并排序"""
    if len(seq) <= 1:
        return seq
    mid = len(seq) // 2  # 将列表分成更小的两个列表
    # 分别对左右两个列表进行处理,分别返回两个排序好的列表
    left = mergesort(seq[:mid])
    right = mergesort(seq[mid:])
    # 对排序好的两个列表合并,产生一个新的排序好的列表
    return merge(left, right)

def merge(left, right):
    """合并两个已排序好的列表,产生一个新的已排序好的列表"""
    result = []  # 新的已排序好的列表
    i = 0  # 下标
    j = 0
    # 对两个列表中的元素 两两对比。
    # 将最小的元素,放到result中,并对当前列表下标加1
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result += left[i:]
    result += right[j:]
    return result

seq = [12,19,17,18,14,11,15,13,16]
print('排序前:',seq)
result = mergesort(seq)
print('排序后:',result)

排序前: [12, 19, 17, 18, 14, 11, 15, 13, 16]
排序后: [11, 12, 13, 14, 15, 16, 17, 18, 19]

TypeError: slice indices must be integers or None or have an index method
将 mid = len(seq) / 2 改成 mid = len(seq) // 2

其他排序:

1. 希尔排序(shellSort):

“基本有序化”可以提升插入排序的效率,将记录序列分成若干子序列,每个子序列分别进行插入排序。需要注意的是,这种子序列是由间隔为某个增量的一组数据组成,即跳跃式选择数据组。

时间复杂度:约在 O ( n 1.25 ) O ( n 1.6 ) O(n^{1.25})和O(n^{1.6}) 之间

def shellSort(list):
	length=len(list)
	dist=length/2
	while dist>0:
		for i in range(dist,length):
			temp=list[i]
			j=i
			while j>=dist and temp<list[j-dist]:
				list[j]=list[j-dist]
				j-=dist
			list[j]=temp
		dist/=2
	return list

2. 堆排序(headSort):

把待排序的数据元素构造成一个完全二叉树结构,则每次选择出一个最大的数据元素只需比较完全二叉树的高度次,即 l o g n logn 次,则排序算法的最好最坏时间复杂度均为 O ( n l o g n ) O(n log n)

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

1.创建最大堆:将堆所有数据重新排序,使其成为最大堆
2.最大堆调整:作用是保持最大堆的性质,是创建最大堆的核心子程序
3.堆排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算

def headSort(list):
	length_list = len(list)
	first=int(length_list/2-1)
	for start in range(first,-1,-1):
		max_heapify(list,start,length_list-1)
	for end in range(length_list-1,0,-1):
		list[end],list[0]=list[0],list[end]
		max_heapify(list,0,end-1)
	return list

def max_heapify(ary,start,end):
	root = start
	while True:
		child = root*2 + 1
		if child > end:
			break
		if child + 1 <= end and ary[child]<ary[child+1]:
			child = child + 1
		if ary[root]<ary[child]:
			ary[root],ary[child]=ary[child],ary[root]
			root=child
		else:
			break

3. 计数排序

计数排序的基本思想是:对每一个输入的元素a[i],确定小于 a[i] 的元素个数。所以可以直接把 a[i] 放到它输出数组中的位置上。假设有5个数小于 a[i],所以 a[i] 应该放在数组的第6个位置上。

def count_sort(list):
	max=min=0
	for i in list:
		if i < min:
			min = i
		if i > max:
			max = i 
	count = [0] * (max - min +1)
	for j in range(max-min+1):
		count[j]=0
	for index in list:
		count[index-min]+=1
	index=0
	for a in range(max-min+1):
		for c in range(count[a]):
			list[index]=a+min
			index+=1
	return list

猜你喜欢

转载自blog.csdn.net/weixin_34275246/article/details/85097914
今日推荐