Python算法(转载GitHub)

Loading [MathJax]/extensions/MathZoom.js

Python算法

排序算法

冒泡排序(Bubble sort)

重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

算法原理: 冒泡排序算法的原理如下:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码实现

    def bubble_sort(collction):
        length = len(collction)
        for i in range(length-1):
        swapped = False
            for j in range(length-1-i):
                if collction[j] > collction[j+1]:
                    swapped = True
                    collction[j],collction[j+1] = collction[j+1],collction[j]
            print(collction)
            if not swapped:break # 如果完成排序,跳出循环
        return collction

    collction = [6,1,7,3,5]

    print(bubble_sort(collction))

桶排序(Bucket sort)

将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。注意:数据的长度必须完全一样。

代码实现

from bubble import bubble_sort 
# 排序方法随便,这里用冒泡
import math
DEFAULT_BUCKET_SIZE = 5
def bucket_sort(myList, bucketSize=DEFAULT_BUCKET_SIZE):
    min = myList[0]
    max = myList[0]

    # 找到最大最小值
    for i in range(len(myList)):
        if myList[i] < min:
            min = myList[i]
        elif myList[i] > max:
            max = myList[i]
    # 初始化桶
    buckets = []
    buckets_count = math.floor((max-min)/bucketSize)+1
    for i in range(0,buckets_count):
        buckets.append([])

    # 将值分别放入桶中
    for i in range(0,len(myList)):
        buckets[math.floor((myList[i]-min)/bucketSize)].append(myList[i])

    # 对桶中的数据排序
    sortArray = []
    for i in range(0, len(buckets)):
        bubble_sort(buckets[i])
        for j in range(0,len(buckets[i])):
            sortArray.append(buckets[i][j])

    return sortArray

if __name__ == '__main__':
    sortArray = bucket_sort([14,16,84,65,32,36,35,21,15,19])
    print(sortArray)

鸡尾酒排序(Cocktail shaker)(双向冒泡排序)

鸡尾酒排序又称双向冒泡排序、鸡尾酒搅拌排序、搅拌排序、涟漪排序、来回排序或快乐小时排序, 是冒泡排序的一种变形。该算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。

原理:使用鸡尾酒排序为一列数字进行排序的过程可以通过右图形象的展示出来: 数组中的数字本是无规律的排放,先找到最小的数字,把他放到第一位,然后找到最大的数字放到最后一位。然后再找到第二小的数字放到第二位,再找到第二大的数字放到倒数第二位。以此类推,直到完成排序。

代码实现

def cocktail_sort(collction):
    for i in range(len(collction)-1, 0,-1):
        swapped = False
        for j in range(i,0,-1):
            if collction[j] < collction[j-1]:
                collction[j], collction[j-1] = collction[j-1], collction[j]
                swapped = True
                print("反:",collction,swapped)

        for j in range(i):
            if collction[j] > collction[j+1]:
                collction[j], collction[j+1] = collction[j+1], collction[j]
                swapped = True
                print("正:",collction,swapped)

        print("总:",collction,swapped)

        if not swapped:break
    return collction

collction = [14,52,11,23,4,26]
print(cocktail_sort(collction))

插入排序(Insertion Sort)

插入排序(Insertion sort)是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

  1. 直接插入排序
  2. 折半插入排序(二分插入排序)

代码实现

    def insertion_sort(collection):
        """将列表分为两部分,前半部分有序,后半部无序。取后半部分元素插入有序列表"""
        for i in range(1,len(collection)):
            while i > 0 and collection[i] < collection[i-1]:
                # 遍历有序表,查找可插入的位置
                collection[i],collection[i-1] = collection[i-1],collection[i]
                i-=1
        return collection

    collection = [5,6,4,5,9,12,7,1]
    print(insertion_sort(collection))

合并排序(Merge Sort)

合并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

合并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。合并排序也叫归并排序。

代码实现

def merge_sort(collection):
    if len(collection) <= 1:
        return collection

    mid = len(collection)//2
    return merge(merge_sort(collection[:mid]),merge_sort(collection[mid:]))

def merge(left,right):
    result = []
    while left and right:
        result.append(left.pop(0) if left[0]<=right[0] else right.pop(0))
    return  result + left + right

collection = [4,51,34,12,6,2,23]
print(merge_sort(collection))

快速排序(QuickSort)

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

代码实现

def quick_sort(collection):
    if len(collection)<=1:
        return collection
    else:
        pivot = collection[0]
        min = [element for element in collection[1:] if element<=pivot]
        max = [element for element in collection[1:] if element>pivot]
    return quick_sort(min) + [pivot] + quick_sort(max)

collection = [-2, -5,-2, -45]
print(quick_sort(collection))

堆排序(Heapsort)

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

堆的操作: 在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:

  • 最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
  • 创建最大堆(Build Max Heap):将堆中的所有数据重新排序
  • 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

代码实现

def heapify(collection, index, heap_size):
    largest = index # 根节点
    left_index = 2 * index + 1
    right_index = 2 * index + 2

    # 如果左右孩子的值大于父节点,交换
    if left_index < heap_size and collection[left_index] > collection[largest]:
        largest = left_index

    if right_index < heap_size and collection[right_index] > collection[largest]:
        largest = right_index

    if largest != index:
        collection[largest], collection[index] = collection[index], collection[largest]
        heapify(collection, largest, heap_size)


def heap_sort(collection):
    n = len(collection)
    # 调整大顶堆 n//2-1是树的层数
    for i in range(n // 2 - 1, -1, -1):
        heapify(collection, i, n)

    # print(collection)
    # 取根节点与树枝交换,从新调整树
    for i in range(n-1, 0, -1):
        collection[0], collection[i] = collection[i], collection[0]
        heapify(collection, 0, i)

    return collection

collection = [0, 5, 3, 2, 2]
print(heap_sort(collection))

基数排序(radix sort)

属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

基本解法 第一步

以LSD为例,假设原来有一串数值如下所示:

73, 22, 93, 43, 55, 14, 28, 65, 39, 81

首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:

0

1 81

2 22

3 73 93 43

4 14

5 55 65

6

7

8 28

9 39

第二步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:

81, 22, 73, 93, 43, 14, 55, 65, 28, 39

接着再进行一次分配,这次是根据十位数来分配:

0

1 14

2 22 28

3 39

4 43

5 55

6 65

7 73

8 81

9 93

第三步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:

14, 22, 28, 39, 43, 55, 65, 73, 81, 93

这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。

LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。

代码实现

def radix_sort(lis):
RADIX = 10 # 基数
placement = 1 # 记录排序的位数
max_digit = max(lis) # 取最大的数

while placement < max_digit: # 位数不超过最大的数
    buckets = [list() for _ in range(RADIX)] # 生成10个桶
    for i in lis: # 按位数的数字放入桶中,个十百
        tmp = int((i / placement) % RADIX)
        buckets[tmp].append(i)

    # 对桶中元素重新排序
    a = 0
    for b in range(RADIX):
        buck = buckets[b]
        for i in buck:
            lis[a] = i
            a += 1

    # 对高一位继续
    placement *= RADIX
return lis


lis = [73, 22, 93, 43, 55, 14, 28, 65, 39, 81]
print(radix_sort(lis))

选择排序(Selection sort)

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。

代码实现

def selection_sort(collection):
length = len(collection)
for i in range(0, length-1):
    least = i # 假设i为第i位最小元素
    for k in range(i + 1, length): # 遍历剩余元素,找到最小元素放到i位
        if collection[k] < collection[least]:
            least = k

    collection[i], collection[least] = collection[least], collection[i]
return collection

collection = [73, 22, 93, 43, 55, 14, 28, 65, 39, 81]
print(selection_sort(collection))

希尔排序(Shell's Sort)

希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。

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

基本思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2

代码实现

def shell_sort(collection):

gaps = [701, 301, 132, 57, 23, 10, 4, 1]

for gap in gaps:
    i = gap
    while i < len(collection):
        temp = collection[i]
        j = i
        while j >= gap and collection[j - gap] > temp:
            collection[j] = collection[j - gap]
            j -= gap
        collection[j] = temp
        i += 1

return collection

collection = [73, 22, 93, 43, 55, 14, 28, 65, 39, 81]
print(shell_sort(collection))

拓扑排序(Topological)

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

执行步骤:由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。

  1. 选择一个入度为0的顶点并输出之;
  2. 从网中删除此顶点及所有出边。

循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列。

代码实现

def topological_sort(start, visited, sort):
current = start
visited.append(current)
neighbors = edges[current]

for neighbor in neighbors:
    if neighbor not in visited:
        sort = topological_sort(neighbor, visited, sort)

sort.append(current)

if len(visited) != len(vertices):
    for vertice in vertices:
        if vertice not in visited:
            sort = topological_sort(vertice, visited, sort)
return sort


sort = topological_sort('a', [], [])
print(sort)

你可能感兴趣的:(Python算法(转载GitHub))