python数据结构相关实现【排序、栈、队列、查找】

本文详细介绍了Python中的几种基本数据结构操作,包括冒泡排序、选择排序、快速排序、插入排序的原理及实现,以及栈和队列的定义与代码实现。此外,还讲解了二分查找算法的概念及其代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、排序【这里介绍冒泡排序、选择排序、快速排序和插入排序】

1. 冒泡排序

(1)原理

解释:冒泡排序,分多轮排序。

1)每一轮都是从上层的第一个数开始与其下一个数进行对比如果大于下一个数就进行交换,下次对比就从上面第二个数【不管之前有无交换】再与其下一个数进行比较,依次比较到最后一个数。【如图 i 的移动变化】

2)第一轮比较【j=0】。比较了最底下第二个数和最底下这个数后,即第一轮比较完。所以第一轮比较的次数为n-1次,即从上面第一个数一直比较到底下第二个数。【其中序列有n个数】。此时一轮获取序列的最大值于最底下。【如图j=0时】

3)第二轮【j=1】的时候,从最上面第一个数开始与下一个数比较。一直到倒数第三个数和倒数第二个数比较完即结束一轮。【最底下的数已经再第一轮已经比较完了,无需再比较】,此时这轮比较的次数为为 n-2次.此时第二大值与底下往上第二个位置

4)之后依次类推。首先观察,每次比较后,都得到一个当前比较序列的最大值依次放入底部排序而上。第一轮整体序列(n个)的最大值于最底部,第二轮除了最底部的那个数的序列(n-1)个数取的最大值与底部往上第二个位置。当获取第n-1大的数与底部往上第n-1个位置时已经比较的轮数为n-1轮。图中 j 即表示轮数的序号【但j从0开始  所以轮序号从j=0到j=n-2 即 n-1轮】

5)而每一轮比较的次数,第一轮(j=0)比较n-1次【n个数】,第二轮(j=1)比较n-2次【n-1个数】,....,第n-1轮(j=n-2)比较1次【2个数】。所以比较次数 i 与 轮序 j 有关系。其中 i = n-1-j。

(2)代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

def bubble(alist):
    """1. 冒泡排序"""
    n = len(alist)
    for j in range(0,n-1):
        """比较轮数"""
        count = 0
        for i in range(0,n-1-j):
            """内层每次循环比较两个元素的次数"""
            if alist[i] > alist[i+1]:
                alist[i],alist[i+1] = alist[i+1],alist[i]
                count+=1
        ### 如果原本有序
        if count == 0:
            return alist
    return alist

if __name__ == '__main__':
    alist = [34, 26, 12, 45, 78, 31]
    result = bubble(alist)
    print(result)

 

2. 选择排序

(1)原理

1)第一次从列表中选出最小值,放在列表最左边;

2)第二次再从后续的列表中选出最小值,放在列表左边的第二个位置;

3)依次类推,直到后续列表全部结束,此时已经将列表全部元素从小到大排列好了;

(2)编程思维

1)  每次选择 要比较列表的 第一个元素为最小值,循环该元素的每一个元素,让后续元素依次与该元素比较

2)如果后续元素比这个元素小,则交换两者的位置。循环完后续所有元素,即得到第一轮比较的最小值位于最左侧第一个位置。

3)每次比较完,要比较列表就会比比上次要比较列表少一个数,这个数已经为上次比较列表的最小值放于左边了。

4)所以外循环为从第一个位置比较到倒数第二个位置。即 j=0 到 j= n-2  即 n-1 次,这个循环确定每次最终得到比较序列的最小值,内层循环比较的范围则从外循环每次确定的最小值位置的下一位置一直比较到最后,即n-1。

(3)代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

def select_sort_a(alist):
    """2.选择排序
    (1) 第一次循环所有数字,选出最小值放在最左边,
    (2) 第二次循环所有(不包含第一个),选出最小值放在最左边第二个位置
    依次类推"""
    n = len(alist)
    for j in range(0,n-1):
        """最外层循环次数"""
        # 默认第一个数为最小
        min_index = j
        for i in range(j+1,n):
            """循环最小值右边的值与最小值进行对比"""
            if alist[i]<alist[min_index]:
                min_index = i
        alist[j],alist[min_index] = alist[min_index],alist[j]
    return alist

if __name__ == '__main__':
    alist1 = [34, 26, 12, 45, 78, 31]
    result = select_sort_a(alist1)
    print(result)

 

3. 快速排序

(1)原理

1) 每次选择一个基准值,把列表分为大于基准值、基准值、小于基准值三部分

2)对小于基准值的列表再选出新的基准值,再进行同样的切分。【大于基准值的列表也同样处理】

3)依次类推,即每次切分出的列表再选基准值,再进行同样的切分,直到切分的列表长度为1时结束。

(2)编程思维

1)因为每次都就进行相同的操作,这里可以使用递归的思想

2)每次切分成三部分,则这里分三部分。大于部分进行递归、小于部分进行递归、再和中间部分连接。即可得到最终排序列表。其中递归的条件是列表长度小于2。

(3)代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

import random

def quick_sort_s(alist):
    """3.快速排序
    (1).首先选出一个基准值,把列表分成大于、小于等于基准值三大块
    (2). 再对小于、大于的小块进行同样的操作"""
    n = len(alist)

    # 基准返回条件:
    if n<2:
        return alist
    else:
        """随机选择列表中的一个序号为基准值索引"""
        jizhun_value_index = random.randint(0,n-1)
        less = [a for a in alist if a<alist[jizhun_value_index]]
        more = [b for b in alist if b>alist[jizhun_value_index]]

    result = quick_sort_s(less)+[alist[jizhun_value_index]]+quick_sort_s(more)
    return result

if __name__ == '__main__':
    alist1 = [34, 26, 12, 45, 78, 31]
    result = quick_sort_s(alist1)
    print(result)


############################### 上述是伪快排,以下才是真正的快速排序

def quick_sort(ls):
    if ls:
        q_sort(ls,0,len(ls)-1)
        return ls
    else:
        return ls

def q_sort(ls,l,r):
    if l<r:
        mid = Partition(ls,l,r)
        q_sort(ls,l,mid-1)
        q_sort(ls,mid+1,r)

def Partition(ls,l,r):
    tmp = ls[l]
    while l<r:
        while l<r and ls[r]>=tmp:
            r-=1
        if l<r:
            ls[l] = ls[r]
        while l<r and ls[l]<=tmp:
            l+=1
        if l<r:
            ls[r] = ls[l]
    ls[l] = tmp
    return l

result = quick_sort([1,0,2,5,6,3,2,5,1,2,5]))
print(result)

4. 插入排序

(1)原理

1)相当于把列表分成两部分(假想两部分,实际只有一个部分),第一次选择列表第一个元素放在最左边这部分,其余元素放在右边这部分。【此时左边部分只有1个元素,右边部分有n-1个元素】

2) 第一次 从右边第一个元素【即整个列表的第二个元素】拿出放到左边的这部分的第二个位置,再与左边部分进行依次向前比较。第一次左边只有一个元素,只需要比较1次。【比较完后,左边2个元素、右边n-2个元素】

3)后续依次类推,即从右边依次取一个数拿到左边的最后面依次与左边元素进行比较。即插入到左边的合适位置。

(2)编程思维

1)  这里需要两层循环,最外层循环控制依次从右边部分取的数索引,这里应该从列表第二个元素开始取(j=1),一直取到最末尾(j=n)

2)内层控制从后面部分取出的数与前面部分依次比较的【取出的数应该放在左边部分最尾部开始依次与前一个元素进行比较】。

3)最坏的情况是,这个取出的数一直向前比较,直到比较左边部分最开始的元素,即i=0索引的元素。此时取出的数索引已经到了i=1的情况。所以最坏情况需要比较到取的数索引至少大于0的情况,即可停止比较。如果取的数依次比较时比要比较的数大,则无需再比较了,可以退出循环。即取的该数比较结束。因为比较数之前的数已经有序了,无需比较。

(3) 代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

def insert_sort_s(alist):
    """插入排序
    依次从第二个数开始取再依次与前面的数进行对比排序"""
    n = len(alist)
    for j in range(1,n):
        i = j
        while i>0:
            if alist[i]<alist[i-1]:
                alist[i],alist[i-1] = alist[i-1],alist[i]
                i-=1
            else:
                break
    return alist

def main():
    alist = [34, 26, 12, 45, 78, 31]
    result = insert_sort_s(alist)
    print(result)

if __name__ == '__main__':
    main()

二、栈与队列

1.栈【stack】

(1) 定义

是一种容器,可存数据元素、访问元素、删除元素。其最大的特点就是只允需从容器的一端【称为栈顶】输入(push)、输出元素(pop)元素;无位置概念,保证任何时候可访问、可删除的元素都是最上面的那个元素。

原理:后进先出【LIFO】

模型如下:

(2)代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

class stack_s(object):
    def __init__(self):
        """ 默认创建一个列表【使用私有变量】"""
        self.__list = []

    def push(self,item):
        """添加一个元素到列表
        【这里默认是选择列表第一个元素为栈底,可自行定义】"""
        self.__list.append(item)

    def pop(self):
        """弹出一个元素【默认栈顶元素】与push相对"""
        self.__list.pop()

    def peek(self):
        """返回栈顶元素"""
        if self.__list:
            return self.__list[-1]
        else:
            return None
    def is_empty(self):
        """判断是否为空"""
        return self.__list == []

    def size(self):
        return len(self.__list)

    def show_list(self):
        return self.__list

if __name__ == '__main__':
    stack = stack_s()
    print("刚创建好的栈元素个数: ",stack.size())
    print("刚创建好的栈是否为空: ",stack.is_empty())
    stack.push(1)
    stack.push(2)
    stack.push(3)
    print("push 1 2 3 元素后的列表: ",stack.show_list())
    print("弹出的栈顶元素是: ",stack.peek())
    stack.pop()
    print("先push 1 2 3 再弹出栈顶元素3后 栈元素个数: ",stack.size())
    print("先push 1 2 3 再弹出栈顶元素3后 栈是否为空: ",stack.is_empty())

2. 队列 【queue】

(1)定义

队列是一种只允许从一端插入操作、另一端进行删除操作的线性表。遵循先进先出(FIFO)准则。

(2)代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

class Queue(object):
    """ 队列 """
    def __init__(self):
        """ 默认创建一个列表【使用私有变量】"""
        self.__list = []

    def in_queue(self,item):
        """添加一个元素到队列
        【这里默认是选择列表第一个元素为,可自行定义】"""
        self.__list.append(item)
        return self.__list

    def out_queue(self):
        """弹出第一个元素,与in相对"""
        return self.__list.pop(0)
        #return self.__list

    def is_empty(self):
        """判断是否为空"""
        return self.__list == []

    def size(self):
        return len(self.__list)

if __name__ == '__main__':
    q = Queue()
    print("刚创建好的队列元素个数: ",q.size())
    print("刚创建好的队列是否为空: ",q.is_empty())
    print("进入第一个元素 3 后的对列",q.in_queue(3))
    print("进入第二个元素 2 后的对列",q.in_queue(2))
    print("进入第三个元素 1 后的对列",q.in_queue(1))

    print("in_queue 3 2 1 后 队列元素个数: ",q.size())
    print("in_queue 3 2 1 后 队列是否为空: ",q.is_empty())

    print("弹出的第一个元素是",q.out_queue())
    print("弹出的第二个元素是",q.out_queue())
    print("弹出的第三个元素是",q.out_queue())

三、二分查找

(1)定义

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

(2)代码实现

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

def binary_search(alist,item):
    """二分查找"""
    n = len(alist)
    low = 0
    high = n-1
    while low<=high:
        mid_index = (low+high)//2
        if alist[mid_index] == item:
            return "找到元素! 在原列表索引为{0}的位置".format(mid_index)

        elif alist[mid_index]<item:
            low = mid_index+1
        else:
            high = mid_index-1
    return "未能找到"

if __name__ == '__main__':
    alist = [1,3,4,9,10,15,17,34]
    result_index1 = binary_search(alist,9)
    result_index2 = binary_search(alist,2)

    print("能否查找到 9:",result_index1)
    print("能否查找到 2:",result_index2)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值