数据结构与算法—线性表

线性结构的特点

  1. 存在唯一一个被称为”第一个“的数据元素
  2. 存在唯一一个被称为”最后一个“的数据元素
  3. 除第一个之外,集合中每一个元素均只有一个前驱
  4. 除最后一个之外,集合中每一个元素均只有一个后继

线性表的定义

用数学语言定义线性表可以表示为 ( a 1 , a 2 . . . a i − 1 , a i , a i + 1 . . . a n ) a i − 1 称 为 a i 的 前 驱 元 素 , a i + 1 称 为 a i 的 后 继 元 素 。 (a_1,a_2...a_{i-1},a_i,a_{i+1}...a_n)a_{i-1}称为a_i的前驱元素,a_{i+1}称为a_i的后继元素。 a1,a2...ai1,ai,ai+1...anai1aiai+1ai

顺序表

顺序表是以数组的形式保存的线性表,具有地址连续的存储单元。
顺序表

顺序表的基本API

python实现的顺序表

  • 初始化
  • 清空顺序表
  • 判断是否为空
  • 获取顺序表的长度
  • 获取指定位置的元素
  • 添加元素
  • 在指定位置插入元素
  • 删除并返回指定位置的元素
  • 第一次元素相等的下标位置


	class Sequence:
	    def __init__(self, n: int):
	        self.__elems = [None for i in range(n)]
	        self.__length = 0
	    
	    def clear(self):
	        self.__length = 0
	    
	    def is_empty(self):
	        if self.__length == 0:
	            return True
	        else:
	            return False
	    
	    def length(self):
	        return self.__length
	    
	    # 获取指定位置的元素
	    def get(self, index: int):
	        if index > self.__length:
	            return None
	        return self.__elems[index]
	
	    # 添加元素
	    def add(self, val):
	        self.__elems[self.__length] = val
	        self.__length += 1
	
	    # 在指定位置插入元素
	    def insert(self, n: int, val):
	        if n > self.__length:
	            return
	        self.__length += 1
	        for i in range(self.__length, n, -1):
	            self.__elems[i] = self.__elems[i-1]
	        self.__elems[n] = val
	    
	    # 删除并返回指定位置的元素
	    def remove(self, n: int):
	        if n > self.__length:
	            return None
	        if n == self.__length:
	            self.__length -= 1
	            return self.__elems[self.__length+1]
	        else:
	            res = self.__elems[n]
	            for i in range(n, self.__length):
	                self.__elems[i] = self.__elems[i+1]
	            self.__length -= 1
	            return res
	
	    # 返回第一次元素相等的下标位置, 如果不存在则返回-1
	    def index_of(self, val):
	        for index,v in enumerate(self.__elems):
	            if v == val:
	                return index
	        return -1

顺序表常见的算法

顺序表的合并

两个原本有序的顺序表合并为新的顺序表,新的顺序表仍然保持有序
顺序表的合并时间复杂度O(la.length + lb.length)



	# 合并两个有序的顺序表,合并后新的顺序表仍然有序
	def merge(la: Sequence, lb: Sequence) -> Sequence:
	    lc = Sequence(la.length()+lb.length())
	    i, j = 0, 0
	    while i < la.length() and j < lb.length():
	        if la.get(i) <= lb.get(j):
	            lc.add(la.get(i))
	            i += 1
	        else:
	            lc.add(lb.get(j))
	            j += 1
	
	    while i < la.length():
	        lc.add(la.get(i))
	        i += 1
	    
	    while j < lb.length():
	        lc.add(lb.get(j))
	        j += 1
	    
	    return lc
	    

链表

链表是一种物理存储单元上非连续、非顺序的存储结构,其物理结构不能只管的表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列的结点(链表中的每一个元素称为结点)组成, 结点可以在运行时动态生成。
链表

链表的基本API

python实现的链表

  • 初始化

  • 清空l链表

  • 判断是否为空

  • 获取链表的长度

  • 获取指定位置的元素

  • 添加元素

  • 在指定位置插入元素
    在这里插入图片描述

  • 删除并返回指定位置的元素
    在这里插入图片描述

  • 第一次元素相等的下标位置


	class Node:
	    def __init__(self, Ldata=None, Lnext=None):
	        self.data = Ldata
	        self.next = Lnext
	
	# 带头结点的单向链表,头节点为空节点
	class LinkList:
	    def __init__(self):
	        self.head = Node()
	        self.__N = 0
	
	    def clear(self):
	        self.head.next = None
	        self.__N = 0
	
	    def length(self):
	        return self.__N
	    
	    def is_empty(self):
	        if self.__N == 0:
	            return True
	        else:
	            return False
	
	    # 获取指定位置元素的值
	    def get(self, index: int):
	        n = self.head
	        for i in range(index+1):
	            n = n.next
	        return n.data
	    
	    def add(self, val):
	        n = self.head
	        while n.next != None:
	            n = n.next
	        node = Node(Ldata=val)
	        n.next = node
	        self.__N += 1
	    
	    # 在指定位置插入节点
	    def insert(self, index: int, val):
	        n = self.head
	        node = Node(Ldata=val)
	        for i in range(index):
	            n = n.next
	        node.next = n.next
	        n.next = node
	        self.__N += 1
	
	    # 删除指定位置的节点,并返回删除节点
	    def remove(self, index: int):
	        n = self.head
	        for i in range(index):
	            n = n.next
	        res = n.next
	        n.next = n.next.next
	        self.__N -= 1
	        return res
	
	    # 返回第一次元素相等的下标位置, 如果不存在则返回-1
	    def index_of(self, val):
	        n = self.head
	        index = -1
	        while n != None:
	            if n.data == val:
	                return index
	            else:
	                n = n.next
	                index += 1
	        return -1

链表常见的算法

链表的合并

两个原本有序的链表合并为新的链表,新的链表仍然保持有序
链表的合并时间复杂度O(la.length + lb.length)


	def merge(la: LinkList, lb: LinkList):
	    p, q = la.head.next, lb.head.next
	    res = l = la.head
	    while p is not None and q is not None:
	        if p.data < q.data:
	            l.next = p
	            l = p
	            p = p.next
	        else:
	            l.next = q
	            l = q
	            q = q.next
	    
	    if p is not None:
	        l.next = p
	    else:
	        l.next = q
	    return res

一元多项式的表示及相加


	class Node:
	    def __init__(self, c=0, e=0):
	        self.coef = c  # 系数
	        self.expn = e  # 指数
	        self.next = None
	
	class Polynomial:
	    def __init__(self):
	        self.head = Node()
	    
	    def add(self, c, e):
	        n = self.head
	        while n.next != None:
	            n = n.next
	        node = Node(c, e)
	        n.next = node
	    
	    # 一元多项式的加法
	    @staticmethod
	    def add_polynomial(p1, p2) -> Node:
	        h1 = p1.head.next
	        h2 = p2.head.next
	        res = p = p1.head
	        while h1 is not None and h2 is not None:
	            if h1.expn < h2.expn:
	                p.next = h1
	                p = h1
	                h1 = h1.next
	            elif h1.expn > h2.expn:
	                p.next = h2
	                p = h2
	                h2 = h2.next
	            else:
	                h1.coef += h2.coef
	                p.next = h1
	                p = h1
	                h1 = h1.next
	                h2 = h2.next
	        
	        if h1:
	            p.next = h1
	        else:
	            p.next = h2
	        return res

判断链表是否有环

实现思路:采用快慢指针

  1. 如何判断是否有环?如果有两个头结点指针,一个走的快,一个走的慢,那么若干步以后,快的指针总会超过慢的指针一圈。
  2. 如何计算环的长度?第一次相遇(超一圈)时开始计数,第二次相遇时停止计数。
  3. 如何判断环的连接点?碰撞点p到连接点的距离=头指针到连接点的距离,所以分别让两个指针从碰撞点和头节点开始走,他们相遇的结点就是连接点。
  4. 如何计算整个链表的长度?根据2和3,链表的长度等于头结点到碰撞点的长度+环的长度。
判断是否有环,慢指针每次走一步,快指针每次走两步

	# 检测链表是否有环
	def judge_hoop(l: LinkList) -> bool:
	    slow = l.head.next
	    fast = l.head.next.next
	    while fast and fast.next:
	        if slow is fast:
	            return True
	        else:
	            slow = slow.next
	            fast = fast.next.next
	    return False
	    
计算环的长度

	# 获取环的长度
	def hoop_length(l: LinkList) -> int:
	    slow = l.head.next
	    fast = l.head.next.next
	    flag = 0
	    num = 0
	    while fast and fast.next:
	        if slow is fast and flag < 2:
	            flag += 1
	        else:
	            if flag == 1:
	                num += 1
	            if flag == 2:
	                num += 1
	                return num
	        slow = slow.next
	        fast = fast.next.next
	    return 0
	    
获取连接点

	# 获取有环链表的连接点
	def link_point(l: LinkList):
	    slow = l.head.next
	    fast = l.head.next.next
	    while fast and fast.next:
	        if slow is fast:
	            break
	        else:
	            slow = slow.next
	            fast = fast.next.next
	    fast = l.head
	    while slow is not fast:
	        slow = slow.next
	        fast = fast.next 
	    return slow
	    
计算链表的长度

	# 计算链表长度
	def link_length(l: LinkList) -> int:
	    hoop = hoop_length(l)
	    n = l.head
	    num = 0
	    while n.next is not link_point(l):
	        num += 1
	        n = n.next
	    return num + hoop
	    

单链表的反转

使用递归的方式实现单链表的反转


	def to_do(n, l):
	    if n.next == None:
	        l.head.next = n
	        return n
	    pre = to_do(n.next, l)
	    if n is l.head:
	        return l.head
	    else:
	        pre.next = n
	        n.next = None
	        return n
	
	# 单链表的反转
	def reverse(l: LinkList):
	    if l.is_empty():
	        return
	    n = to_do(l.head, l)
	    return l.head
	    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值