【2】线性表 - 王道考研

目录

2 线性表

2.1 线性表的定义和基本操作

2.2 顺序表

2.2.1 顺序表的定义

2.2.2 顺序表上基本操作的实现

2.3 链表

2.3.1 单链表的定义

2.3.2 单链表上基本操作的实现

2.3.3 双链表

2.3.4 循环链表

2.3.5 静态链表

2.3.6 顺序表与链表的比较

2.4 总结


2 线性表

2.1 线性表的定义和基本操作

2.2 顺序表

2.2.1 顺序表的定义

  • 注意区分顺序表与数组的下标

  • 动态分配和静态分配都是分配连续空间

2.2.2 顺序表上基本操作的实现

a=[1,2,3,6,6,7]
# 插入-前插法
a.insert(0,6)
# 插入-后插法
a.append(5)
# 删除
a.pop(2)
# 查找
a.index(2)
  • 插入

    • 一般使用 前插法 
    • 将插入位置之后的元素向后平移一位
    • 时间复杂度 O(n)
  • 删除

    • 将删除位置之后的元素依次往前平移一位
    • 时间复杂度 O(n)
  • 查找

2.3 链表

2.3.1 单链表的定义

  •  每个元素:data 和 指针域

  • 引入头节点,有两个优点:
     
    • 第一个位置和其他位置操作的天涯
    • 空表和非空表操作的统一(例如判断是否为空表)

 

2.3.2 单链表上基本操作的实现

class SingleNode():
    def __init__(self, item):
        self.item = item
        self.next = None


class SingleLinkList():
    def __init__(self):
        # using headNode
        self._headNode = SingleNode(None)

    def is_empty(self):
        return self._headNode.next == None

    def length(self):
        cur = self._headNode.next
        i=0
        while cur!=None:
            i += 1
            cur=cur.next
        return i

    def travel(self):
        if self.is_empty():
            return None
        cur=self._headNode.next
        while cur!=None:
            print(cur.item)
            cur=cur.next

    def tail_insert(self,i,item):
        # insert a node right after location(i)
        new_node = SingleNode(item)
        pre = self.GetElm(i)
        new_node.next=pre.next
        pre.next=new_node

    def head_insert(self,i,item):
        # insert a node right before location(i)
        new_node=SingleNode(item)
        pre=self.GetElm(i-1)
        new_node.next=pre.next
        pre.next=new_node

    def GetElm(self,i):
        # get element by index
        if self.is_empty():
            return None
        if i<1:
            return self._headNode

        cur=self._headNode.next
        while (cur!=None) & (i>1):
            cur=cur.next
            i-=1
        if i>1:
            # exceed the length of LinkList
            return None
        else:
            return cur

    def LocateElm(self,Elm):
        # locate the index of given element
        cur = self._headNode.next
        i=1
        while cur!=None:
            if cur.item==Elm:
                return i
            cur=cur.next
            i+=1
        return None

    def construct_by_headInsert(self,node_list):
        # O(n)
        length=len(node_list)
        self._headNode.next=SingleNode(node_list[length-1])
        for i in range(1,length):
            new_node=SingleNode(node_list[length-1-i])
            new_node.next=self._headNode.next
            self._headNode.next=new_node

    def construct_by_tailInsert(self,node_list):
        # O(n)
        cur=self._headNode
        for item in node_list:
            cur.next=SingleNode(item)
            cur=cur.next

    def remove_by_index(self,i):
        pre=self.GetElm(i-1)
        tmp=pre.next
        pre.next=tmp.next
        del tmp

    def remove_by_item(self,item):
        i=self.LocateElm(item)
        self.remove_by_index(i)

    def remove_by_address(self,node):
        # O(1)
        # step1 swap
        afr=node.next
        node.item=afr.item
        node.next=afr.next
        # step2 delete
        del afr

L=SingleLinkList()
L.construct_by_headInsert([5,3,2,1,7])
L2=SingleLinkList()
L2.construct_by_tailInsert([5,3,2,1,7])
  • 建立
    • 头插法 O(n)
    • 尾插法
  • 查找
    • 按序号查找 & 按值查找
  • 插入
    • 前插法 O(n)
      • 先查找
      • 再修改(修改的顺序不能反)
    • 后插法 O(1)
      • 直接在给定位置插入元素即可(不需要查找)
      • 可以使用 后插法 实现 前插法
        • 先使用后插法插入元素,然后交换两元素位置
  • 删除
    • 给定下标
    • 给定节点地址
      • 普通:先查找,再删除 O(n)
      • 加速:先交换,后删除 O(1)
  • 求表长
    • 加入头节点的另一个好处:空表和非空表操作的统一(例如判断是否为空表)

2.3.3 双链表

class DNode():
    def __init__(self,item):
        self.item=item
        self.next=None
        self.pre=None

class DoubleLineList():
    def __init__(self):
        self._headNode=DNode(None)

    def is_empty(self):
        return self._headNode.next==None

    def length(self):
        cur=self._headNode.next
        i=0
        while cur!=None:
            i+=1
            cur=cur.next
        return i

    def travel_forward(self):
        if self.is_empty():
            return None
        cur = self._headNode.next
        while cur != None:
            print(cur.item)
            cur = cur.next
            
    def travel_backward(self):
        if self.is_empty():
            return None
        cur = self._headNode.next
        while cur.next != None:
            cur = cur.next
        while cur.pre!=None:
            print(cur.item)
            cur=cur.pre

    def GetElm(self, i):
        # get element by index
        if self.is_empty():
            return None
        if i < 1:
            return self._headNode

        cur = self._headNode.next
        while (cur != None) & (i > 1):
            cur = cur.next
            i -= 1
        if i > 1:
            # exceed the length of LinkList
            return None
        else:
            return cur

    def tail_insert(self,i,item):
        # insert a node right after location(i)
        # O(1)
        pre=self.GetElm(i)
        new_node=DNode(item)

        if pre.next==None:
            pre.next=new_node
            new_node.pre=pre
        else:
            new_node.next=pre.next
            new_node.pre=pre

            pre.next.pre = new_node
            pre.next=new_node

    def remove_by_adress(self,node):
        pre=node.pre
        pre.next=node.next
        node.next.pre=pre

    def construct_by_tailInsert(self,node_list):
        length=len(node_list)
        cur = self._headNode
        pre = self._headNode
        for item in node_list:
            new_node=DNode(item)
            cur.next=new_node
            new_node.pre=cur
            cur=cur.next

L=DoubleLineList()
L.construct_by_tailInsert([1,5,2,6,9])
L.travel_backward()
L.travel_forward()
L.tail_insert(5,1)
  • 定义
    • 特点:引入了前驱指针(prior *)
    • 注意:双链表没有尾节点,因此操作不是统一的
  • 插入 O(1)
  • 删除 O(1)

 

2.3.4 循环链表

循环单链表

class SingleNode():
    def __init__(self, item):
        self.item = item
        self.next = None


class SinCycLinkList():
    def __init__(self):
        # using head pointer
        self._phead=None

    def is_empty(self):
        return self._phead == None

    def length(self):
        cur = self._phead
        i=1
        while cur.next!=self._phead:
            i += 1
            cur=cur.next
        return i

    def travel(self):
        if self.is_empty():
            return None
        cur=self._phead
        while cur.next!=self._phead:
            print(cur.item)
            cur=cur.next
        print(cur.item)

    def tail_insert(self,i,item):
        # insert a node right after location(i)
        new_node = SingleNode(item)
        if i==0:
            last_node=self.GetElm(self.length())
            new_node.next=self._phead
            self._phead=new_node
            last_node.next=self._phead
        else:
            pre = self.GetElm(i)
            new_node.next=pre.next
            pre.next=new_node

    def head_insert(self,i,item):
        # insert a node right before location(i)
        new_node=SingleNode(item)
        if i==1:
            last_node = self.GetElm(self.length())
            new_node.next = self._phead
            self._phead = new_node
            last_node.next = self._phead
        else:
            pre=self.GetElm(i-1)
            new_node.next=pre.next
            pre.next=new_node

    def GetElm(self,i):
        # get element by index
        if self.is_empty():
            return None
        if i<1:
            return None

        cur=self._phead
        while (cur.next!=self._phead) & (i>1):
            cur=cur.next
            i-=1
        if i>1:
            # exceed the length of LinkList
            return None
        else:
            return cur

    def LocateElm(self,Elm):
        # locate the index of given element
        cur = self._phead
        i=1
        while cur.next!=self._phead:
            if cur.item==Elm:
                return i
            cur=cur.next
            i+=1
        if cur.item==Elm:
            return i
        return None

    def construct_by_headInsert(self,node_list):
        # O(n)
        length=len(node_list)
        last_node=SingleNode(node_list[length-1])
        self._phead=last_node
        for i in range(1,length):
            new_node=SingleNode(node_list[length-1-i])
            new_node.next=self._phead
            self._phead=new_node
        last_node.next=self._phead

    def construct_by_tailInsert(self,node_list):
        # O(n)
        self._phead=SingleNode(node_list[0])
        cur=self._phead
        for i in range(1,len(node_list)):
            cur.next=SingleNode(node_list[i])
            cur=cur.next
        cur.next=self._phead

    def remove_by_address(self,node):
        if node.next==self._phead:
            # O(n)
            pre=self.GetElm(self.length()-1)
            pre.next=self._phead
            del node
        else:
            # O(1)
            # step1 swap
            afr=node.next
            node.item=afr.item
            node.next=afr.next
            # step2 delete
            del afr

L=SinCycLinkList()
L.construct_by_tailInsert([5,3,2,1,7])
L2=SinCycLinkList()
L2.construct_by_headInsert([5,3,2,1,7])

循环双链表

2.3.5 静态链表

  • 定义:
    • 用数组实现链表结构
    • next存的是下一个节点的下标
    • -1表示是最后一个节点
    • 静态链表不能动态扩展
    • 适用于没有指针的语言

 

 

2.3.6 顺序表与链表的比较

  • 存取方式:
  • 逻辑结构和物理结构

  • 基本操作 -- 时间复杂度

  • 内存空间

  • 怎么选择

  • 三个常用操作,分别选择什么数据结构
    • 最值 - 遍历 【时间 O(n)】
    • 逆序 - 对换位置
顺序表【时间O(n)空间O(1)】链表【时间O(n) 空间 O(1)】

 

  • 归并
顺序表【时间O(n+m) 空间O(n+m)】链表【时间O(n) 空间 O(1) 或 O(0)(不创建新链表)】

 

2.4 总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值