zoukankan      html  css  js  c++  java
  • python数据结构和算法3 栈、队列和排序

    顺序表和链表都是线性表,线性数据

    stack,也叫堆栈,是一种容器,可存入元素、访问元素、删除元素,特点是只允许在容器的一端(栈顶,top)进行加入数据(压栈,push)和输出数据(pop),按照后进先出(LIFO,last in first out)的原理运作。

    栈的实现

    class Stack(object):
        """栈"""
        def __init__(self):
            self.__list = []
    
        def push(self, item):
            """添加一个新的元素item到栈顶"""
            return self.__list.append(item)
    
        def pop(self):
            """弹出栈顶元素"""
            return self.__list.pop( )
    
        def peek(self):
            """返回栈顶元素"""
            if self.__list:
                return self.__list[-1]
            else:
                return None
    
        def is_empty(self):
            """判断栈是否为空"""
            # return self.__list 不可以这样写,调用is_empty直接使用内部列表了
            # 空列表代表是假,"",{},(),[]都是假
            return self.__list == []
    
        def size(self):
            """返回栈的元素个数"""
            return len(self.__list)
    
    if __name__=="__main__":
        s = Stack()
        s.push(1)
        s.push(2)
        s.push(3)
        s.push(4)
        print(s.pop())
        print(s.pop())
        print(s.pop())
        print(s.pop())

    队列

    也是线性容器,只能从一端添加,从另一端去取,排队,先进先出

    class Queue(object):
        """队列"""
        def __init__(self):
            self.__list = []
        def enqueue(self, item):
            """往队列中添加一个item元素"""
            self.__list.append(item)
        def dequeue(self):
             """从队列头部删除一个元素"""
             return self.__list.pop(0)
        def is_empty(self):
            """判断一个队列是否为空"""
            return self.__list == []
        def size(self):
            """返回队列的大小"""
            return len(self.__list)
    
    if __name__=="__main__":
        s = Queue()
        s.enqueue(1)
        s.enqueue(2)
        s.enqueue(3)
        s.enqueue(4)
        print(s.dequeue())
        print(s.dequeue())
        print(s.dequeue())
        print(s.dequeue())

    排序算法

    sorting algorithm 将一串数据按特定顺序进行排序的算法

    排序算法的稳定性,稳定排序算法会让原本有相等键值的纪录维持相对次序。

    冒泡排序

    def bubble_sort(alist):
        """冒泡排序"""
        n = len(alist)
        for j in range(len(alist)-1,0,-1):
            for i in range(j):
                if alist[i] > alist[i+1]:
                    alist[i],alist[i+1] = alist[i+1],alist[i]
    
    li = [54,26,93,17,77,31,44,55,20]
    bubble_sort(li)
    print(li)

    选择排序

    它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

    def select_sort(alist):
        n = len(alist)
        for i in range(n-1):
            min_index = i
            for j in range(i+1, n):
                if alist[j] < alist[min_index]:
                    min_index = j
            # 如果选择的数据不在正确位置,进行交换
            if min_index != i:
                alist[i], alist[min_index] = alist[min_index], alist[i]
    
    alist = [12,1,54,22,31,3]
    select_sort(alist)
    print(alist)

    插入排序

    insertion sort ,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

    左边有序,右边无序,从右边取出第一个往左边挪,从右往左依次比较确定自己的位置。

    def insert_sort(alist):
        """插入元素"""
        #第二个位置开始往前插入,下标为1
        for i in range(1,len(alist)):
            # 从第i个元素开始往前比较,小于前一个,换位置
            for j in range(i,0,-1):
                if alist[j] < alist[j-1]:
                    alist[j],alist[j-1] = alist[j-1],alist[j]
    
    alist = [54,11,44,35,67,99,5]
    insert_sort(alist)
    print(alist)

    希尔排序

    希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序的基本思想是:将数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。最后整个表就只有一列了。

    def shell_sort(alist):
        n = len(alist)
        # 初始步长
        gap = n//2
        while gap>0:
            for i in range(gap, n):
                j = i
                while j>=gap and alist[j]<alist[j-gap]:
                    alist[j-gap],alist[j] = alist[j],alist[j-gap]
            gap = gap//2
    
    if __name__ == "__main__":
        alist = [54,26,93,17,77,31,44,55,20]
        shell_sort(alist)
        print(alist)

    快速排序

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

    步骤为:

    1. 从数列中挑出一个元素,称为"基准"(pivot),
    2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
    3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

    排序代码参考快速排序上的,课件上的太繁琐

    def quick_sort(alist):
        if len(alist) <= 1:
            return alist
    
        # 左边存放小于基准的数字
        left = []
        # 右边存放大于基准的数字
        right = []
        # 基准数字
        base = alist.pop()
    
        # 对原数组进行划分
        for i in alist:
            if i < base:
                left.append(i)
            else:
                right.append(i)
    
        # 递归调用
        return quick_sort(left) + [base] + quick_sort(right)
    
    def main():
        alist = [1,4,7,5,2,8,9,6,3,10]
        print(quick_sort(alist))
    main()

    归并排序

    采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。

    将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

    def merge_sort(alist):
        if len(alist)<=1:
            return alist
        num = len(alist)//2
        left = merge_sort(alist[:num])
        right = merge_sort(alist[num:])
        # 合并
        return merge(left, right)
    
    def merge(left, right):
        """合并操作,将left[]和right[]合并"""
        # left,right的下标指针
        l,r = 0,0
        result = []
        while l<len(left) and r<len(right):
            if left[l]<right[r]:
                result.append(left[l])
                l += 1
            else:
                result.append(right[r])
                r += 1
        result += left[l:]
        result += right[r:]
        return result
    
    alist = [54,26,93,17,77,31,44,55,20]
    sorted_alist = merge_sort(alist)
    print(sorted_alist)

    常见排序算法比较

    搜索

    二分查找

    也叫折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。条件:有序的顺序表 

    def binary_search(alist,item):
        """二分查找,递归"""
        n = len(alist)
        if n>0:
            mid = n//2
            if alist[mid]==item:
                return True
            elif item<alist[mid]:
                return binary_search(alist[:mid], item)
            else:
                return binary_search(alist[mid+1:],item)
        return False
    
    def binary_search_2(alist,item):
        """二分查找,非递归"""
        n = len(alist)
        first = 0
        last = n-1
        while first<=last:
            mid = (first+last)//2
            if alist[mid]==item:
                return True
            elif item<alist[mid]:
                last = mid -1
            else:
                first = mid + 1
        return False
    
    if __name__=="__main__":
        alist = [0, 1, 2, 8, 13, 17, 19, 32, 42, ]
        print(binary_search(alist, 3))
        print(binary_search(alist, 13))
        print(binary_search_2(alist, 3))
        print(binary_search_2(alist, 13))

    时间复杂度

    • 最优时间复杂度:O(1)
    • 最坏时间复杂度:O(logn)
  • 相关阅读:
    硬盘安装CentOS 6.0(超级详细图文教程)
    js获取当前URL、域名、端口号
    前端匹配表情
    记一次复杂的数据转换
    浅拷贝与深拷贝
    js统计数组中元素的重复次数(二)
    js计算数组中某个元素重复出现的个数(一)
    移动端——处理rem根字体
    js实现简单的双向绑定
    JS正则截取两个字符串之间的字符串
  • 原文地址:https://www.cnblogs.com/wangjinliang1991/p/9898899.html
Copyright © 2011-2022 走看看