算法_經常使用排序算法

目錄

1、冒泡排序html

2、選擇排序算法

3、插入排序shell

4、快速排序app

5、堆排序dom

6、歸併排序ide

7、基數排序函數

8、希爾排序ui

9、桶排序spa

10、總結設計

 

1、冒泡排序

一、思路:首先,列表每兩個相鄰的數比較大小,若是前邊的比後邊的大,那麼這兩個數就互換位置。就像是冒泡同樣

二、代碼關鍵點:

  • 趟數:n-1趟
  • 無序區

三、圖示說明:依次類推就會獲得排序結果。冒泡排序的效率仍是很低的

四、代碼示例

# 思路:列表中兩個相鄰的數比較大小,若是前邊的比後邊的大,那麼這兩個就互換位置
def bubblr_sort(li):
    for i in range(1,len(li)-1):#表示趟數
        change = False
        for j in range(len(li)-i):  #表示無序區,無序區的範圍爲0,len(li)-i
            if li[j] > li[j+1]:
                li[j],li[j+1] = li[j+1],li[j]
                change = True

        if not change:
            return

li = list(range(10))
import random
random.shuffle(li)
print(li)
bubblr_sort(li)
print(li)



def bubblr_sort(li,reverse=False):
    for i in range(1,len(li)-1):#表示趟數
        change = False
        for j in range(len(li)-i):  #表示無序區,無序區的範圍爲0,len(li)-i
            if not reverse:
                # 從小到大排序
                if li[j] > li[j+1]:
                    li[j],li[j+1] = li[j+1],li[j]
                    change = True
            else:
                # 從大到小排序
                if li[j] < li[j+1]:
                    li[j],li[j+1] = li[j+1],li[j]
                    change = True

        if not change:
            return

li = list(range(10))
import random
random.shuffle(li)
print(li)
bubblr_sort(li,True)
print(li)
冒泡算法

五、時間複雜度:O(n**2)

2、選擇排序

一、思路:一趟遍歷完記錄最小的數,放到第一個位置;在一趟遍歷記錄剩餘列表中的最小的數,繼續放置

二、代碼關鍵點:

  • 無序區
  • 最小數的位置

三、問題:怎麼選出最小的數?

import random
def select_sort(li):
    for i in range(len(li)-1):
        #i 表示躺數,也表示無序區開始的位置
        min_loc = i  #最小數的位置
        for j in range(i+1,len(li)):  #i  ,i+1,就是後一個位置的範圍
            # [9, 2, 1, 6, 5, 8, 3, 0, 7, 4]
            # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
            if li[j] <li[min_loc]:  #兩個位置進行比較,若是後面的一個比最小的那個位置還小,說明就找到最小的了
                min_loc = j   #找到最小的位置
        li[i],li[min_loc] = li[min_loc],li[i]  #吧找到的兩個值進行互換位置
li = list(range(10))
random.shuffle(li)
print(li)
select_sort(li)
print(li)
選擇排序

四、時間複雜度:O(n**2)

3、插入排序

一、思路:元素被分爲有序區和無序區兩部分。最初有序區只有一個元素。每次從無序區中選擇一個元素,插入到有序區的位置,直到無序區變空。

二、代碼關鍵點:

  • 摸到的牌
  • 手裏的牌

三、圖示說明

插入後:

四、代碼示例

import random
def insert_sort(li):
    for i in range(1,len(li)):
        #i 表示無序區的第一個數
        tmp = li[i]  #摸到的牌
        j = i-1 #指向有序區最後一個位置
        while li[j] >tmp and j>=0:
            #循環終止條件 li[j]<=tmp  and j==-1
            li[j+1] = li[j]  #向後移動
            j-=1
        li[j+1] = tmp
        
li = list(range(10))
random.shuffle(li)
print(li)
insert_sort(li)
print(li)
View Code

4、快速排序

一、思路:一、取一個元素p(第一個元素),是元素p歸位(去它該去的地方);

     二、列表被p分紅兩部分,左邊的都比p小,右邊的都比p大;

     三、遞歸完成排序

二、算法關鍵點

  • 歸位
  • 遞歸

三、圖示說明

四、怎麼歸併呢?先把5取出來,這時候就會有一個空位,從右邊找比5小的數填充過來,如今右邊有一個空位了,從左邊找比5大的放到右邊的空位上。依次類推,

只要left和right碰在一塊兒,這樣就找打5的位置了

如圖示:

圖一圖二

 圖三圖四

 這樣在把找到的5的位置放進去去ok了

五、代碼示例

import time
def wrapper(func):
    def inner(*args,**kwargs):
        start = time.time()
        ret = func(*args,**kwargs)
        end = time.time()
        print('%s running time :%s'%(func.__name__,start-end))
        return ret
    return inner


def partition(li,left,right):
    '''歸位函數'''
    tmp = li[left]  #先把5取出來
    while left < right:
        while left < right and li[right] >= tmp:  #若是降序排列修改li[right] <= tmp
                right -= 1 #從右邊找比5小的數,填充到5的位置
        li[left] = li[right]
        while left < right and li[left] <= tmp:  #若是降序排列修改li[right] >= tmp
                left += 1# 從左邊找比5大的數字放在右邊的空位
        li[right] = li[left]
    li[left] = tmp  #當跳出循環條件的時候說明找到了,而且把拿出來的5在放進去
    return left


def _quick_sort(li,left,right):
    '''快速排序的兩個關鍵點:歸位,遞歸'''
    if left < right:  #至少有兩個元素,才能進行遞歸
        mid = partition(li,left,right)  #找到歸位的位置
        _quick_sort(li,left,mid-1)  #遞歸,右邊的-1
        _quick_sort(li,mid+1,right) #遞歸,左邊的+1

@wrapper
def quick_sort(li):
    return _quick_sort(li, 0, len(li)-1)

@wrapper
def sys_sort(li):
    '''系統排序'''
    li.sort()

import random
li = list(range(100000))
random.shuffle(li)
# print(li)
quick_sort(li)
# print(li)

sys_sort(li)  

#結論:系統的排序要比快排的時間快的多
# quick_sort running time :-0.6240355968475342
# sys_sort running time :-0.002000093460083008
快速排序算法

六、快速排序的時間複雜度O(nlogn)

5、堆排序

一、堆排序過程:

  • 一、創建堆
  • 二、獲得堆頂元素,爲最大元素
  • 三、去掉堆頂,將堆最後一個元素放在堆頂,此時可經過一次調整從新使堆有序
  • 四、堆頂元素爲第二大元素
  • 五、重複步驟3,直到堆變空

二、代碼示例

import random

def _sift(li, low, high):
    """
    :param li:
    :param low: 堆根節點的位置
    :param high: 堆最有一個節點的位置
    :return:
    """
    i = low  # 父親的位置
    j = 2 * i + 1  # 孩子的位置
    tmp = li[low]  # 原省長
    while j <= high:
        if j + 1 <= high and li[j + 1] > li[j]:  # 若是右孩子存在而且右孩子更大
            j += 1
        if tmp < li[j]:  # 若是原省長比孩子小
            li[i] = li[j]  # 把孩子向上移動一層
            i = j
            j = 2 * i + 1
        else:
            li[i] = tmp  # 省長放到對應的位置上(幹部)
            break
    else:
        li[i] = tmp  # 省長放到對應的位置上(村民/葉子節點)


def sift(li, low, high):
    """
    :param li:
    :param low: 堆根節點的位置
    :param high: 堆最有一個節點的位置
    :return:
    """
    i = low         # 父親的位置
    j = 2 * i + 1   # 孩子的位置
    tmp = li[low]   # 原省長
    while j <= high:
        if j + 1 <= high and li[j+1] > li[j]: # 若是右孩子存在而且右孩子更大
            j += 1
        if tmp < li[j]: # 若是原省長比孩子小
            li[i] = li[j]  # 把孩子向上移動一層
            i = j
            j = 2 * i + 1
        else:
            break
    li[i] = tmp



def heap_sort(li):
    n = len(li)
    # 1. 建堆
    for i in range(n//2-1, -1, -1):
        sift(li, i, n-1)
    # 2. 挨個出數
    for j in range(n-1, -1, -1):    # j表示堆最後一個元素的位置
        li[0], li[j] = li[j], li[0]
        # 堆的大小少了一個元素 (j-1)
        sift(li, 0, j-1)


li = list(range(10))
random.shuffle(li)
print(li)
heap_sort(li)
print(li)

# li=[2,9,7,8,5,0,1,6,4,3]
# sift(li, 0, len(li)-1)
# print(li)
堆排序

待看http://www.cnblogs.com/haiyan123/p/8400537.html

6、歸併排序

假設如今的列表分兩段有序,如何將其合成爲一個有序列表。這種操做稱爲一次歸併

一、思路:

二、歸併關鍵字

  • 分解:將列表越分越小,直至分紅一個元素
  • 終止條件:一個元素是有序的
  • 合併:將兩個有序列表歸併,列表愈來愈大

三、圖實示例:https://www.cnblogs.com/chengxiao/p/6194356.html

四、代碼示例:

import random
def merge(li, low, mid, high):
    # 一次歸併
    '''
    :param li: 列表
    :param low: 起始位置
    :param mid: 按照那個位置分
    :param high: 最後位置
    :return:
    '''
    i = low
    j = mid + 1
    ltmp = []
    while i <= mid and j <= high:
        if li[i] < li[j]:
            ltmp.append(li[i])
            i += 1
        else:
            ltmp.append(li[j])
            j += 1
    while i <= mid:
        ltmp.append(li[i])
        i += 1
    while j <= high:
        ltmp.append(li[j])
        j += 1
    li[low:high+1] = ltmp


def _merge_sort(li, low, high):
    if low < high:  # 至少兩個元素
        mid = (low + high) // 2
        _merge_sort(li, low, mid)
        _merge_sort(li, mid+1, high)
        merge(li, low, mid, high)
        print(li[low:high+1])


def merge_sort(li):
    return _merge_sort(li, 0, len(li)-1)


li = list(range(16))
random.shuffle(li)
print(li)
merge_sort(li)

print(li)
歸併排序

五、歸併排序的時間複雜度:O(nlogn),空間複雜度是:O(n)

7、基數排序

 

8、希爾排序

一、思路:

  • 希爾排序是一種分組插入排序算法。
  • 首先取一個整數d1=n/2,將元素分爲d1個組,每組相鄰量元素之間距離爲d1,在各組內進行直接插入排序;
  • 取第二個整數d2=d1/2,重複上述分組排序過程,直到di=1,即全部元素在同一組
  • 希爾排序每趟並不使某些元素有序,而是使總體數據愈來愈接近有序;最後一趟排序使得全部數據有序。

二、代碼實現

def insert_sort(li):#插入排序
    for i in range(1, len(li)):
        # i 表示無序區第一個數
        tmp = li[i] # 摸到的牌
        j = i - 1 # j 指向有序區最後位置
        while li[j] > tmp and j >= 0:
            #循環終止條件: 1. li[j] <= tmp; 2. j == -1
            li[j+1] = li[j]
            j -= 1
        li[j+1] = tmp

def shell_sort(li):#希爾排序  與插入排序區別就是把1變成d
    d = len(li) // 2
    while d > 0:
        for i in range(d, len(li)):
            tmp = li[i]
            j = i - d
            while li[j] > tmp and j >= 0:
                li[j+d] = li[j]
                j -= d
            li[j+d] = tmp
        d = d >> 1




li=[5,2,1,4,5,69,20,11]
shell_sort(li)
print(li)
希爾排序

希爾排序的複雜度特別複雜,取決於d,分組的長度2、位移運算符

9、桶排序

在計數排序中,若是元素的範圍比較大(好比在1到1億之間),如何改造算法?

     桶排序,首先將將元素分在不一樣的桶中,在對每一個桶中的元素排序。

多關鍵字排序

先對十位進行排序,再根據 十位進行排序

要用兩個函數,一個用來裝桶,一個用來出桶

默認10個桶,找到個位,十位,分別放在對應的桶裏的位置

 

     桶排序的表現取決於數據的分佈。也就是須要對不一樣數據排序時採起不一樣的分桶策略。

     平均狀況時間複雜度:O(n+k)

     最壞狀況時間複雜度:O(n+k)

     空間複雜度:O(nk)

    先分紅若干個桶,桶內用插入排序。

 

例子

1:給兩個字符串S和T,判斷T是否爲S的從新排列後組成的單詞:

  s="anagram",t="nagaram",return true

   s='cat',t='car',return false

代碼以下:

s = "anagram"
t = "nagaram"

def ss(s,t):
    return  sorted(list(s))==sorted(list(t))
y=ss(s,t)
print(y)

二、給定一個m*n的而爲列表,查找一個數是否存在。[[1,3,5,7],[10,11,16,20],[23,30,34,50]],列表有下列特性:每一行的列表從左到右已經排序好;每一行第一個數比上一行最後一個數大。

def searchMatrix(matrix, target):
    m = len(matrix)
    # print('m', m)
    if m == 0:
        return False
    n = len(matrix[0])
    if n == 0:
        return False
    low = 0
    high = m * n - 1
    # print('high',high)
    while low <= high:
        mid = (low + high) // 2
        x, y = divmod(mid, n)
        if matrix[x][y] > target:
            high = mid - 1
        elif matrix[x][y] < target:
            low = mid + 1
        else:
            return True
    else:
        return False


s = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
# print(searchMatrix(s, 1))
# print(searchMatrix(s, 2))
# print(searchMatrix(s, 3))
# print(searchMatrix(s, 4))
# print(searchMatrix(s, 5))
# print(searchMatrix(s, 6))
print(searchMatrix(s, 7))
# print(searchMatrix(s, 8))
# print(searchMatrix(s, 9))
View Code

3.給定一個列表和一個整數,設計算法找兩個數的小標,使得兩個數之和爲給定的整數。保證確定僅有一個結果。

     例如:列表[1,2,5,4]與目標整數3,1+2=3,結果爲(0,1)

方式一:

方式二:

方式三

方式四和三同樣

def twoSum(num, target):
    dict = {}
    for i in range(len(num)):
        print(dict)
        x = num[i]
        if target - x in dict:
            return dict[target - x], i
        dict[x] = i



l = [1, 2, 5, 4]
print(twoSum(l, 7))

10、總結

LOw B 三人組

  • 冒泡排序,選擇排序,直接插入排序他們的時間複雜度都是O(n^2),空間複雜度是O(1)

NB 三人組

  • 快速排序,歸併排序,堆排序他們的時間複雜度都是O(nlogn)
  • 三種排序算法的缺點
    • 快速排序:極端狀況下排序效率低
    • 歸併排序:須要額外的內存開銷
    • 堆排序:在快的排序算法中相對較慢

挨着換的穩定,不挨着換的不穩定

 

 

參考or轉發

http://www.cnblogs.com/haiyan123/p/8395926.html

相關文章
相關標籤/搜索