排序问题

排序问题考察的很多,这里有一个排序问题的动画演示,不过再用动画来演示也要自己多遍手写来熟悉原理和流程
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
另一个可视化算法的地方:https://visualgo.net/en

quick sort:

重点在partition和终止条件。如果是用stack,则模拟preorder的stack性质。

# quick sort, recursive
def qs(arr, start, end):
    if start < end:
        index = partition(arr, start, end)
        qs(arr, start, index-1)
        qs(arr, index+1, end)

def partition(arr, start, end):
    # use start as pivot
    # from IPython.core.debugger import Tracer; Tracer()() 
    pivot = arr[start]
    i = start + 1
    j = end
    while i <= j:
        while i <= j and arr[i] <= pivot:
            i += 1
        while i <= j and arr[j] >= pivot:
            j -= 1
        if i < j:
            arr[i], arr[j] = arr[j], arr[i]
    # swap pivot with j
    arr[start], arr[j] = arr[j], arr[start]
    return j

partition函数的另一种写法,利用最后一个值作为pivot

def partition(arr, start, end):
    pos = start # use the end value as pivot
    for i in range(start, end):           # i must be between start and end-1
        if arr[i] < arr[end]:
            arr[i],arr[pos] = arr[pos],arr[i]
            pos += 1

    arr[pos],arr[end] = arr[end],arr[pos] # you forgot to put the pivot
                                          # back in its place
    return pos

非递归写法

# 快速排序,非递归写法,类似于preorder traversal
def qsort_stack(arr):
    stack = [(0, len(arr)-1)]
    while stack:
        i, j = stack.pop()
        index = partition(arr, i, j)
        if j > index + 1:
            stack.append((index+1, j))
        if i < index - 1:
            stack.append((i, index-1))
quick select

利用partition过程中,每次站好队的那个元素和其index

def select(vector, left, right, k):
    "Returns the k-th smallest, (k >= 0), element of vector within vector[left:right+1] inclusive."
    while True:
        index = partition(vector, left, right)
        dist = index - left  # 找到一个值,放好位置,和k做比较
        if dist == k:
            return vector[index] # 如果当前index正好是k,那么就返回值
        elif k < dist:              
            right = index - 1
        else:
            k -= dist + 1
            left = index + 1

merge sort:

merge sort是要用额外空间的,但是它是有序的。如果既要有序又要inplace,可以用bubble sort

# mergesort
def ms(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) / 2
    arr1 = ms(arr[:mid])
    arr2 = ms(arr[mid:])
    return merge(arr1, arr2)

def merge(arr1, arr2):
    arr = []
    p1 = 0
    p2 = 0
    while p1 < len(arr1) and p2 < len(arr2):
        if arr1[p1] > arr2[p2]:
            arr.append(arr2[p2])
            p2 += 1
        else:
            arr.append(arr1[p1])
            p1 += 1
    return arr + arr1[p1:] + arr2[p2:]

bubble sort

先排好最大值(把最大值放到最后一个),然后再排倒数第二大的值。

# bubble sort
def bs(arr):
    for i in range(len(arr)-1, -1, -1):
        for j in range(i):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]

selection sort

从后往前,对于第i 位,选取0~i位中最大的和i位swap

# selection sort
def ss(arr):
    for i in range(len(arr)-1, -1, -1):
        pos = 0
        for j in range(i+1):
            if arr[pos] < arr[j]:
                pos = j
        arr[pos], arr[i] = arr[i], arr[pos]

insertion sort:

插入排序可以保持前列有序,然后依次向后排序

# insertion sort
def ins(arr):
    for i in range(len(arr)):
        val = arr[i]
        pos = i
        while pos > 0 and arr[pos-1] > val:
            arr[pos] = arr[pos-1]
            pos -= 1
        arr[pos] = val
shell sort

利用gap减少了insertion sort的comparison的次数,应该不会考。

# shell sort
def ss(arr):
    sub = len(arr)/2
    while sub > 0:
        for start in range(sub):
            gapins(arr,start,sub)
        print "After increments of size",sub, "The list is",arr

        sub = sub / 2

def gapins(arr,start,gap):
    for i in range(start+gap,len(arr),gap):

        val = arr[i]
        pos = i
        while pos >= gap and arr[pos-gap] > val:
            arr[pos] = arr[pos-gap]
            pos = pos-gap

        arr[pos] = val

heap sort

def hs(arr):
    # 先建立一个heap,然后把最大值依次取出放到最后一位,这是inplace的做法
    for start in range((len(arr)-2)/2, -1, -1):
        siftdown(arr, start, len(arr)-1)
    
    for end in range(len(arr)-1, 0, -1):
        arr[end], arr[0] = arr[0], arr[end]
        siftdown(arr, 0, end - 1)
    return arr

def siftdown(arr, start, end):
    root = start
    while True:
        child = root * 2 + 1
        if child > end: 
            # 如果root没有子结点
            break
        if child + 1 <= end and arr[child] < arr[child + 1]:
            # 如果root有两个子结点,那么选择其中较大的那个
            child += 1
        if arr[root] < arr[child]:
            # 把root的节点下移到子结点,然后重复这个操作
            arr[root], arr[child] = arr[child], arr[root]
            root = child
        else:
            break

counting sort

适合range不太大的数的count,比如说数字符串,复杂度为:O(n+k) k就是range,n是要排序的个数。

def cs(s):
    # 对一个字符串排序
    count = [0 for i in range(26)]
    output = ["" for _ in s]
 
    # 存贮在count上存贮每一个字符出现的次数
    for c in s:
        count[ord(c)-ord("a")] += 1
 
    # 做一个prefix sum,这样就可以知道每一个字符的实际位置
    for i in range(1, 26):
        count[i] += count[i-1]
 
    # 创建一个输出arr,
    for c in s:
        output[count[ord(c)-ord("a")]-1] = c
        count[ord(c)-ord("a")] -= 1
    return output

bucket sort

对于一个range里均匀分布的问题,比如说一堆在0,1之间的float进行排序,这里不能用counting sort,因为counting sort需要用到index
bucketSort(arr[], n)

  1. Create n empty buckets (Or lists).
  2. Do following for every array element arr[i].
    .......a) Insert arr[i] into bucket[n*array[i]]
  3. Sort individual buckets using insertion sort.
  4. Concatenate all sorted buckets.
def bsort(A):
  """Returns A sorted. with A = {x : x such that 0 <= x < 1}."""
    buckets = [[] for x in range(10)]
    for i, x in enumerate(A):
        buckets[int(x*len(buckets))].append(x)
    out = []
    for buck in buckets:
        out += isort(buck)
    return out
    
def isort(A):
    if len(A) <= 1: return A
    i = 1
    while i < len(A):
        k = A[i]
        j = i - 1
        while j >= 0 and A[j] > k:
            A[j+1] = A[j]
            A[j] = k
            j -= 1      
        i += 1
    return A

radix sort

radix sort

def radix_sort(arr, radix=10):
    k = int(math.ceil(math.log(max(arr), radix)))
    for i in range(1, k+1):
        bucket = [[] for k in range(radix)]
        for j in arr:
            bucket[j/(radix**(i-1)) % radix].append(j)
        arr = sum(bucket, [])
    return arr

Kth Largest Element in an Array: 这题看起来简单,但是解法很多。https://leetcode.com/problems/kth-largest-element-in-an-array/#/solutions

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容