python 中 列表就是一个顺序表

有序顺序表 比 普通顺序表 查找速度快一点,但是时间复杂度还是O(n)

二分查找法

可以大大减少查找的数据项,  时间复杂度是O(log(n))

# 循环版本的二分查找
my_list = [1, 2, 19, 23, 53, 68, 79]


def binary_search(a_list, item):
    first = 0
    last = len(a_list) - 1
    found = False

    while first <= last and not found:
        mid = (first + last) // 2
        if a_list[mid] == item:
            found = True
        else:
            if a_list[mid] > item:
                last = mid - 1
            else:
                first = mid + 1
    return found


print(binary_search(my_list, 19))
# 二分查找的递归方法
my_list = [1, 2, 19, 23, 53, 88, 99]


# 注意,不用列表切片的原因是,列表切片的复杂度是O(n)
def binary_search(a_list, item, first, end):
    # 结束条件
    if first > end:
        return False
    mid = (first + end) // 2
    if a_list[mid] == item:
        return True
    # 缩小规模
    elif a_list[mid] > item:
        # 调用自身
        return binary_search(a_list, item, first, mid - 1)
    else:
        # 调用自身
        return binary_search(a_list, item, mid + 1, end)


print(binary_search(my_list, 19, 0, len(my_list) - 1))

缺点: 虽然二分查找的速度要快于顺序查找,但是二分查找的条件是列表是有序排列的。 得到有序排列的列表也是需要消耗很多计算资源的。所以,如果列表的内容经常变化,则不建议使用二分查找。

冒泡排序

python find_element有多个 python find list_数据项

# 冒泡排序
# 总需要n-1趟,随着趟数的增加,比对次数逐步从n-1减少到1,并包括可能发生的n次数据项交换。
# 第一趟,对比n-1次,第二趟,对比n-2次,第n-1趟,对比1次。
# 最大时间复杂度O(n^2),效率很差,有个优点是无序额外的存储空间开销


def bubble_sort(a_list):
    for compare_times in range(len(a_list) - 1, 0, -1):  # 从len(alist)-1 到 1
        for i in range(compare_times):
            if a_list[i] > a_list[i + 1]:
                a_list[i], a_list[i + 1] = a_list[i + 1], a_list[i]


def bubble_sort_optimization(a_list):
    for compare_times in range(len(a_list) - 1, 0, -1):  # 从len(alist)-1 到 1
        exchange = False  # 优化
        for i in range(compare_times):
            if a_list[i] > a_list[i + 1]:
                exchange = True  # 优化
                a_list[i], a_list[i + 1] = a_list[i + 1], a_list[i]
        if not exchange:  # 优化
            break


my_list = [4, 3, 2, 1]
bubble_sort(my_list)
print(my_list)

选择排序

# 选择排序对交换进行了削减,相比起冒泡排序进行多次交换,每趟仅进行1次交换,记录最大项的所在位置,最后再跟本趟最后一项交换

def select_sort(a_list):
    for pass_num in range(len(a_list) - 1, 0, -1):
        max_value_index = 0
        for i in range(1, pass_num+1):
            if a_list[max_value_index] < a_list[i]:
                max_value_index = i
        a_list[max_value_index], a_list[pass_num] = a_list[pass_num], a_list[max_value_index]


my_list = [12, 34, 5, 2, 3, 5, 672, 34, 2, 1]
select_sort(my_list)
print(my_list)

插入排序

就和打牌的时候排序一样

python find_element有多个 python find list_快速排序_02

python find_element有多个 python find list_二分查找_03

# 插入排序 写法一


def insert_sort(a_list):
    for index in range(1, len(a_list)):
        current_value = a_list[index]  # 新项/插入项
        position = index

        while position >= 1 and a_list[position - 1] > current_value:
            # 比对移动
            a_list[position] = a_list[position - 1]
            position = position - 1

        a_list[position] = current_value  # 插入新项


my_list = [34, 5, 5, 1, 23, 4, 7, 4, 34, 45, 6, 47, 98, 3, 2, 57, 46]
insert_sort(my_list)
print(my_list)
# 插入排序 写法二
def insert_sort(lst):
    for i in range(1, len(lst)):
        for j in range(i, 0, -1):
            if lst[j-1] > lst[j]:
                lst[j-1], lst[j] = lst[j], lst[j-1]
            else:
                break


a_list = [54, 26, 93, 17, 77, 31, 44, 55, 20]
insert_sort(a_list)
print(a_list)

 

谢尔排序(shell排序)

# 谢尔排序

def shell_sort(a_list):
    sub_list_count = len(a_list) // 2
    while sub_list_count > 0:
        for start_position in range(sub_list_count):
            gap_insert_sort(a_list, start_position, sub_list_count)
        print("After increaments of size", sub_list_count, "The list is", a_list)
        sub_list_count = sub_list_count // 2


def gap_insert_sort(a_list, start, gap):
    for i in range(start + gap, len(a_list), gap):
        current_value = a_list[i]
        position = i

        while position >= gap and a_list[position - gap] > current_value:
            a_list[position] = a_list[position - gap]
            position = position - gap

        a_list[position] = current_value


my_list = [3, 123, 2, 4, 123, 2, 52, 45, 45, 6, 2, 3.45, 3, 342, 13, 2134, 1234, 12]
shell_sort(my_list)


#After increaments of size 9 The list is [3, 2, 2, 3, 123, 2, 52, 45, 12, 6, 123, 3.45, 4, 342, 13, 2134, 1234, 45]
#After increaments of size 4 The list is [3, 2, 2, 3, 4, 2, 13, 3.45, 12, 6, 52, 45, 123, 45, 123, 2134, 1234, 342]
#After increaments of size 2 The list is [2, 2, 3, 2, 4, 3, 12, 3.45, 13, 6, 52, 45, 123, 45, 123, 342, 1234, 2134]
#After increaments of size 1 The list is [2, 2, 2, 3, 3, 3.45, 4, 6, 12, 13, 45, 45, 52, 123, 123, 342, 1234, 2134]
# shell 排序2
def shell_sort(lst):
    n = len(lst)
    gap = n // 2
    while gap > 0:
        for i in range(gap, n):
            j = i
            while j >= gap and lst[j - gap] > lst[j]:
                lst[j - gap], lst[j] = lst[j], lst[j - gap]
                j -= gap

        gap = gap // 2


a_list = [54, 26, 93, 17, 77, 31, 44, 55, 20]
shell_sort(a_list)
print(a_list)

归并排序

python find_element有多个 python find list_数据项_04

注意到归并排序算法使用了额外1倍的存储空间用于归并, 这个特性在对特大数据集进行排序的时候,要考虑进去

时间复杂度比前面几个好一点,前面的都是O(n^2) , 归并排序是O(nlog(n))

# 归并排序
def merge_sort(lst):
    # 结束条件
    # 调用自身
    # 减小规模

    if len(lst) <= 1:
        return lst

    middle = len(lst) // 2
    left = merge_sort(lst[:middle])  # 左半部分排好序
    right = merge_sort(lst[middle:])  # 右半部分排好序

    # 合并左右部分,完成排序
    merged = []
    while left and right:
        if left[0] <= right[0]:
            merged.append(left.pop(0))
        else:
            merged.append(right.pop(0))

    merged.extend(right if right else left)
    return merged


my_list = [34, 5, 5, 1, 23, 3, 2, 4, 34, 45, 6, 47, 98, 4, 7, 57, 46]
print(merge_sort(my_list))

快速排序

依据一个“中值”数据项来把数据表分成两半: 小于中值的一半和大于中值的一半,然后每部分分别进行快速排序(递归)

def quick_sort(alist, start, end):
    """快速排序"""

    # 递归的退出条件
    if start >= end:
        return

    # 设定起始元素为要寻找位置的基准元素
    mid = alist[start]

    # low为序列左边的由左向右移动的游标
    low = start

    # high为序列右边的由右向左移动的游标
    high = end

    while low < high:
        # 如果low与high未重合,high指向的元素不比基准元素小,则high向左移动
        while low < high and alist[high] >= mid:
            high -= 1
        # 将high指向的元素放到low的位置上
        alist[low] = alist[high]

        # 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
        while low < high and alist[low] < mid:
            low += 1
        # 将low指向的元素放到high的位置上
        alist[high] = alist[low]

    # 退出循环后,low与high重合,此时所指位置为基准元素的正确位置
    # 将基准元素放到该位置
    alist[low] = mid

    # 对基准元素左边的子序列进行快速排序
    quick_sort(alist, start, low - 1)

    # 对基准元素右边的子序列进行快速排序
    quick_sort(alist, low + 1, end)


alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
quick_sort(alist, 0, len(alist) - 1)
print(alist)

散列:

什么是散列? 

散列数据结构, 可以将数据查找的次数降低到常数级。 也就是由数据项的值来确定其存放的位置!

散列表, 又称哈希表,是一种数据集,其中数据项的存储方式尤其有利于将来快速的查找定为

散列表中的每一个存储位置,称为槽slot, 可以用来保存数据项, 每个槽有一个唯一个名词

python 自带散列函数库hashlib

# 对单字符串(小的数据项)进行散列计算
import hashlib

print(hashlib.md5("hello world!".encode()).hexdigest())
print(hashlib.sha1("hello world!".encode()).hexdigest())
# 对数据量很大的数据进行哈希计算的时候(比如电影视频),可以分部分计算
import hashlib
m = hashlib.md5()
m.update("hello world!".encode())
m.update("this is part #2".encode())
m.update("this is part #3".encode())
print(m.hexdigest())