算法入门——数组,链表,选择排序

目录

内存的工作原理

数组和链表

数组

 链表

 比较

整体比较

时间复杂度

python中实现链表

测试

 选择排序

小结


内存的工作原理

大家逛超市的时候,应该都看见过门口有储存柜,进去逛超市时,就把东西存入储存柜,如果你东西很多,就可能需要开两个柜子来放你的东西,然后你就只需要拿着储存柜小票轻轻松松去逛超市了,等逛完超市,你凭借小票在把自己的东西拿出来。其实计算机内存的工作原理大致就是这样。计算机就是超市门口这一堆储物柜的集合,每个单独的储物柜都有对应的小票,都有它们的地址。

当我们需要将数据存储到内存时,我们请求到计算机,计算机再分配给我们一片空间用于存储。

数组和链表

数组

数组(Array)是有序的元素序列。它的所有元素在内存中是相连的(紧靠在一起的)。

 链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,即链表中的元素可储存在内存的任何地方。链表中存储了每个元素即下一个元素的地址,所以在插入元素的情况下,它比数组更具有优势,因为它只需要将元素存入内存,然后将其地址储存在上一个元素中,不需像数组那样将后面的元素依次退位。

 比较

整体比较

数组链表
内存占用需要连续的内存空间不需要连续的内存空间
大小可变固定,分配多少就是多少,不能动态扩展,可能会浪费内存链表的大小可动态变化
插入(中间)较慢,需要将插入元素之后的所有元素往后移动较快,只需要放入内存,并将其地址放入前一个元素
删除较慢,需要将删除元素之后的所有元素往前移较快,只需要修改前一个元素的指向的地址即可
查询较快,可以通过下标直接访问较慢,只能通过遍历查询
访问形式即可随机访问也可顺序访问只能顺序访问
扩展性不可动态扩展可以动态扩展
存储数据类型必须一致可以不一致

时间复杂度

查询插入删除
数组O(1)O(n)O(n)
链表O(n)O(1)O(1)

需要说明的是,数组如果通过下标随机查询,它的时间复杂度为O(1),但如果通过顺序访问,那么时间复杂度和链表一样为O(n),但如果这是个有序数组,通过顺序访问,那么根据二分查找,它的时间复杂度为O(logn)。上面的插入,删除仅仅指这一个操作,并不包含查询的时间,之所以数组的插入和删除操作的时间复杂度为O(n),是因为数组插入和删除一个元素时,其他元素的位置也要相应移动,在头部和尾部插入(注意考虑内存是否足够,足够时时间复杂度为O(1))的时间复杂度都为O(n),而链表只需要插入元素,再在前一个元素中添加地址即可,所以时间复杂度为O(1),总的来说,不能过于记住结论,需要实际情况灵活分析。

在实际生活中,其实数组用的情况更多,因为它支持随机访问,你想要哪个元素,你可以通过下标直接跳到你想要的元素,所有它的读取速度更快,而在生活中,很多情况都要求能够随机访问。

python中实现链表

下面会简单演示单向链表的实现。双向链表,循环链表的实现大家可以去看看这篇文章

Python 数据结构之链表 - 知乎

单向链表实现,具有增删检查等功能,主要运用类与对象等知识

# @Time:2022/1/2813:21
# @Author:中意灬
# @File:链表.py
# @ps:tutu qqnum:2117472285
# #定义结点
class Node(object):
    #单向链表的节点
    def __init__(self,item):
        self.item=item#item存放数据元素
        self.next=None#next是下一个节点的标识
class SingleLinkList(object):
    #单向链表
    def __init__(self):
        self.head=None

    def is_empty(self):
        #判断链表是否为空
        return self.head == None
    def length(self):
        #链表长度
        #初始指针指向head头部
        cur=self.head
        count=0
        #指针指向None表示达到了尾部
        while cur != None:
            count+=1
            #指针下移
            cur=cur.next
        return count

    def items(self):
        #遍历链表
        #获取head指针
        cur=self.head
        #循环遍历
        while cur is not None:
            #返回生成器
            yield cur.item
            cur=cur.next
    def add(self,item):
        #向链表头部添加元素
        node=Node(item)
        #新节点指针指向原头部节点
        node.next=self.head
        #头部节点指针修改为新节点
        self.head=node
    def append(self,item):
        #尾部添加元素
        node=Node(item)
        #先判断是否为空链表
        if self.is_empty():
            #空链表,head指向新节点
            self.head=node
        else:
            #不是空链表,找到尾部,将尾部next节点指向新节点
            cur=self.head
            while cur.next != None:
                cur=cur.next
            cur.next=node
    def insert(self, index, item):
        # 指定位置插入元素
        # 指定位置在第一个元素之前,在头部插入
        if index <= 0:
            self.add(item)
        # 指定位置超过尾部,在尾部插入
        elif index > (self.length() - 1):
            self.append(item)
        else:
            # 创建元素结点
            node = Node(item)
            cur = self.head
            # 循环到需要插入的位置
            for i in range(index - 1):
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        #删除元素
        cur = self.head
        pre = None
        while cur != None:
            # 找到指定元素
            if cur.item == item:
                # 如果第一个就是删除的节点
                if not pre:
                    # 将头指针指向头节点的后一个节点
                    self.head = cur.next
                else:
                    # 将删除位置前一个节点的next指向删除位置的后一个节点
                    pre.next = cur.next
                return True
            else:
                # 继续按链表后移节点
                pre = cur
                cur = cur.next

    def find(self, item):
        #查找元素是否存在
        return item in self.items()

测试

if __name__ == '__main__':
    link_list=SingleLinkList()
    #添加元素
    for i in range(5):
        link_list.append(i)
    print('节点:',end='')
    for i in link_list.items():
        print(i, end='\t')
    #头部插入元素
    link_list.add(6)
    print('插入头部元素后:',end='')
    for i in link_list.items():
        print(i, end='\t')
    #尾部添加元素
    link_list.append(10)
    print('尾部添加元素后:',end='')
    for i in link_list.items():
        print(i,end='\t')
    #中间插入元素
    print('')
    link_list.insert(3,9)
    print('中间插入元素后:',end='')
    for i in link_list.items():
        print(i, end='\t')
    #删除元素
    link_list.remove(3)
    print('删除元素后:',end='')
    for i in link_list.items():
        print(i, end='\t')
    #查找元素
    a=link_list.find(4)
    print('是否查找到4这个元素:',end='')
    print(a)

运行结果:

 选择排序

假如辅导员让你做成绩分析,让你对整个专业的绩点进行一个从高到低的排序,该如何做?

姓名平均绩点
张三2.1
李四3.2
老五4.2
王麻子0.8

一种办法是遍历这个列表,找出绩点最高的人,然后添加到一个新的列表,然后重复这个操作,就能得到一个有序列表,而这便是选择排序,时间复杂度为O(n^2)

另外一种方法是用快速排序的方法来实现,时间复杂度为O(nlogn),比选择排序较快。这里只讲解选择排序,后面再谈快速排序。

这是降序排序,升序思想一样

# @Time:2022/1/301:02
# @Author:中意灬
# @File:选择排序.py
# @ps:tutu qqnum:2117472285
#找出最大元素,返回其下标
def find_Max_num(arr):
    Max_num=arr[0]
    Max_num_index=0
    for i in range(1,len(arr)):
        if arr[i]>Max_num:
            Max_num=arr[i]
            Max_num_index=i
    return Max_num_index
#排序
def sort_num(arr):
    newArr=[]
    for i in range(len(arr)):
        Max_num_index=find_Max_num(arr)
        newArr.append(arr.pop(Max_num_index))#找到一个,弹出一次,再次循环
    return newArr
if __name__ == '__main__':
    arr=[3.1,3.5,0.2,4.2]
    new=sort_num(arr)
    print(new)

 运行结果:

[4.2, 3.5, 3.1, 0.2]

小结

  • 计算机内存如一大堆储物柜
  • 储存多个元素是,可使用数组或链表
  • 数组的元素地址连着一起
  • 链表的元素地址分开的,其中每个元素都包含着下一个元素的地址
  • 数组有两种访问方式,随机访问和顺序访问,随机访问速度很快
  • 链表只有一种访问方式,顺序访问,访问速度较慢
  • 链表的插入和删除速度很快,数组较慢
  • 在同一个数组中,所有元素的类型都必须一样,链表可以不一致
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值