python算法复习(一)----排序算法

从头复习一遍算法,顺便整理一下笔记。

# 选择排序
# 时间复杂度 O(n^2)
# 每一趟在n-i+1个记录中选择关键字最小的记录作为序列中的第i个记录。
import random


def select_sort(arr):
    if arr == [] or len(arr) < 2:
        return arr
    for i in range(len(arr)):
        minimumindex = i
        for j in range(i + 1, len(arr)):
            if arr[minimumindex] > arr[j]:
                minimumindex = j
        arr[minimumindex], arr[i] = arr[i], arr[minimumindex]
    return arr


# 冒泡排序
# 时间复杂度 O(n^2)
# 大的东西沉底,汽泡上升。
def bubble_sort(arr):
    if arr == [] or len(arr) < 2:
        return arr
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr


# 插入排序
# 时间复杂度 O(n^2)
# 从0位置开始依次保证0~0\0~1\0~2上面有序.在i位置往前看,保证有序就停下来
# 因为思想是前面的数已经有序了,所以只要保证当前位置和前一位有序,就代表前面所有的数都有序了,就可以停下来
def insert_sort(arr):
    if arr == [] or len(arr) < 2:
        return arr
    for i in range(len(arr)):
        j = i - 0
        while True:
            if j < 0 or arr[j] < arr[i]:
                break
            else:
                arr[i], arr[j] = arr[j], arr[i]
                i = j
                j = j - 1
    return arr


# 归并排序
# 时间复杂度O(n*log(n))
# 用二分法往下递归,从最底层向上依次保持每一层的有序性
def merge(larr, rarr):
    p1 = 0
    p2 = 0
    helplist = []
    while p1 < len(larr) and p2 < len(rarr):
        if larr[p1] < rarr[p2]:
            helplist.append(larr[p1])
            p1 += 1
        else:
            helplist.append(rarr[p2])
            p2 += 1
    if p1 != len(larr):
        for i in range(p1, len(larr)):
            helplist.append(larr[i])
    else:
        for i in range(p2, len(rarr)):
            helplist.append(rarr[i])
    return helplist


def merge_sort(arr, l, r):
    if arr == [] or len(arr) < 2:
        return arr
    if l >= r:
        helplist = []
        helplist.append(arr[l])
        return helplist
    m = int((l + r) / 2)
    left = merge_sort(arr, l, m)
    right = merge_sort(arr, m + 1, r)
    helplist = merge(left, right)
    return helplist


# 归并排序引生(非常重要,所以放到了这里)
# 求小和问题(求一组数据中每个数左边有多少个数比当前数小,求出比当前数小的总和)
# 因为是从底层回溯的,所以不需要看已经merge过的数,只需要看右边有多少个比当前的大
def small_sum_merge(larr, rarr):
    p1 = 0
    p2 = 0
    helplist = []
    minsum = 0
    while p1 < len(larr) and p2 < len(rarr):
        if larr[p1] < rarr[p2]:
            helplist.append(larr[p1])
            minsum += larr[p1] * (len(rarr) - p2)
            p1 += 1
        else:
            helplist.append(rarr[p2])
            p2 += 1
    if p1 != len(larr):
        for i in range(p1, len(larr)):
            helplist.append(larr[i])
    else:
        for i in range(p2, len(rarr)):
            helplist.append(rarr[i])
    return helplist, minsum


def small_sum(arr, l, r):
    if arr == [] or len(arr) < 2:
        return arr
    if l >= r:
        helplist = []
        helplist.append(arr[l])
        return helplist, 0
    m = int((l + r) / 2)
    left, lsum = small_sum(arr, l, m)
    right, rsum = small_sum(arr, m + 1, r)
    helplist, minsum = small_sum_merge(left, right)
    print(minsum)
    minsum = minsum + lsum + rsum
    return helplist, minsum


# 快速排序
# 快排1:用数组的最后一位数作荷兰国旗问题,然后再把这个数和大于区域内的第一位作交换;然后在大于和小于区域重复这个过程
# 快排2:随机从数组中取一个数作为划分标准num
def partition(arr, l, r):
    num = arr[random.randint(l, r)]
    i = l
    p1 = l - 1
    p2 = r + 1
    while i <= r and i < p2:
        if arr[i] < num:
            arr[i], arr[p1 + 1] = arr[p1 + 1], arr[i]
            p1 += 1
            i += 1
        elif arr[i] == num:
            i += 1
        else:
            arr[i], arr[p2 - 1] = arr[p2 - 1], arr[i]
            p2 -= 1
    return arr, p1, p2


def quick_sort(arr, l, r):
    if arr == [] or len(arr) < 2:
        return arr
    if l >= r:
        return
    arr, less, more = partition(arr, l, r)
    quick_sort(arr, l, less)
    quick_sort(arr, more, r)
    return arr


# 堆排序
# 说到了堆,不如直接手写一个简单的小根堆吧
# 堆结构
# 完全二叉树,从左往右依次变满的就是完全二叉树
# 手写一个小根堆
class HeapNode(object):
    # 定义堆的节点结构,就是在二叉树节点的基础上加上一个父节点的信息
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None
        self.father = None

    def __repr__(self):
        return str(self.value)


class Small_root_pile(object):
    def __init__(self):
        self.root = None

    def insert(self, node):
        # inset的思想很简单,就是在保证是完全二叉树的基础上保证父节点用于比自己小
        # 所以就是在基本的完全二叉树的基础上在添加节点的地方加上一个heapinsert的过程
        node = HeapNode(node)
        queue = [self.root]
        if self.root == None:
            self.root = node
            self.root.father = self.root
            return
        else:
            while True:
                if queue == []:
                    break
                else:
                    cur = queue.pop(0)
                    # 先进先出,如果先进去的也就是上层的节点有空的子节点就优先补上;如果不为空,就把自己的子节点加进去
                    if cur.left == None:
                        # 如果左边为空就加到左边
                        cur.left = node
                        cur.left.father = cur
                        self.heapinsert(cur.left)
                        return
                    else:
                        queue.append(cur.left)
                    if cur.right == None:
                        cur.right = node
                        cur.right.father = cur
                        self.heapinsert(cur.right)
                        return
                    else:
                        queue.append(cur.right)

    def heapinsert(self, node):
        # 不断的看父节点是不是比自己小
        while True:
            cur = node.father
            if node.value < cur.value:
                cur.value, node.value = node.value, cur.value
                node = cur
            else:
                break

    def pop(self):
        # 弹出就是把头节点和最后一个节点交换然后再heapify
        if self.root == None:
            return
        queue = [self.root]
        while True:
            cur = queue.pop(0)
            if cur.left != None:
                queue.append(cur.left)
            if cur.right != None:
                queue.append(cur.right)
            if queue == []:
                popvalue = self.root.value
                self.root.value = cur.value
                if cur.father.right != None:
                    cur.father.right = None
                elif cur.father.left != None:
                    cur.father.left = None
                else:
                    self.root = None
                    return popvalue

                self.heapify(self.root)
                return popvalue

    def heapify(self, head):
        # 不断的看子节点有没有比自己小的
        while True:
            if head.left != None and head.right == None:
                if head.left.value < head.value:
                    head.value, head.left.value = head.left.value, head.value
                    head = head.left
                else:
                    return
            elif head.left != None and head.right != None:
                if head.left.value < head.right.value:
                    if head.left.value < head.value:
                        head.value, head.left.value = head.left.value, head.value
                        head = head.left
                    else:
                        return
                else:
                    if head.right.value < head.value:
                        head.value, head.right.value = head.right.value, head.value
                        head = head.right
                    else:
                        return
            else:
                return


def heap_sort(arr):
    heap = Small_root_pile()
    for i in arr:
        heap.insert(i)
    helplist = []
    while heap.root != None:
        helplist.append(heap.pop())

    return helplist


# 桶排序(基数排序)
# 实际上就是从个位每一位进行排序
def bucket_sort(arr):
    digit = 0
    themax=max(arr)
    while themax != 0:
        digit += 1
        themax=int(themax/10)
    getDigitnum=lambda x,d:int(x/(10**(d-1))%10)

    for d in range(1,digit+1):
        bucket=[]
        for i in range(10):
            bucket.append([])
        for i in range(len(arr)):
            digitnum=getDigitnum(arr[i],d)
            bucket[digitnum].append(arr[i])
        arr=[]
        for i in bucket:
            for j in i:
                arr.append(j)
    return arr

'''
总结:
    一、什么是稳定性:
        同样值的个体之间,如果不要为排序而改变相对位置,这个排序就是稳定的,否则就是不稳定的.
    2.稳定排序:
        ①冒泡排序:      O(N^2)  O(1)
            1-2、2-3,依次比较交换确定最后一位的值
        ②插入排序:      O(N^2)  O(1)
            依次确定0-0、0-1上面的排序,如果存在大小关系就交换
        ③归并排序:      O(N*logN)   O(N)
            二分法递归再归并,在左右两个指针相同时先放入左边指针则稳定
        ④基数排序:      
            从个位数开始排序,直到最高位排完
    3.不稳定排序:
        ①选择排序:      O(N^2)  O(1)
            在列表中遍历把最小值放到前面去
        ②快速排序:      O(N*logN)   O(logN)
            将数组先快排一次不断在左右两侧递归快排,当i指向的数<num时与小于范围外的第一个数交换,i和小于范围都+1。
            当>num时,于大于范围外的第一个数做交换,大于范围+1
            当==num时,i+1
        ③堆排序:       O(N*logN)   O(1)
            先将数组变成大根堆,再把第一个和最后一个数做交换确定最大值,再将剩下的数组变成大根堆,重复以上
'''

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值