详解Python中有关链表操作的理论知识及leetcode面试例题及要点分析

往期回顾:

Python数据结构之链表


链表结构:

数组之后,链表结构是最常用的数据结构。引用维基百科中的话:链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表(数组)快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。

链表作为一种基础的数据结构可以用来生成其它类型的数据结构如堆栈或队列。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接(“links”)。如下图所示,以单向链表为例。
在这里插入图片描述
单向链表和双向链表:

单向链表:

单向链表通过一个外部的头链接来访问第1项,单向链表的节点被分成两个部分,第一部分保存或显示关于节点的信息,第二部分储存下一节点地址。单向链表只能向一个方向遍历。单向链表中每个节点只有一个指针。单向链表的结构图如下所示:

在这里插入图片描述
双向链表中每个节点有两个指针,一个指向前一节点,另一个指向后一节点。最后一项没有指向下一项的指针,第一项没有指向前一项的指针。在双向链表中还有一个外部的tail指针,它允许直接访问结构中的最后一个节点。其结构图如下所示:

双向链表:

详解Python中有关链表操作的理论知识及leetcode面试例题及要点分析_第1张图片

链表无法进行随机访问,只能进行顺序访问。链表分配内存的方式和数组不同,在链表中插入或删除点时,可以直接进行插入或删除,不需要在内存中移动数据项;每一次插入和删除的过程,链表会调整大小,不需要额外的内存代价,也不需要复制数据项。

非连续性内存和节点:

数组必须存储在连续的内存中,即数组中项的逻辑顺序和内存中的物理单元是紧密耦合的;而链表中项的逻辑顺序和物理单元是解耦的。链表中的内存为非连续性的。

链表中的基本单位是节点,单向链表的节点包含:数据项、指向下一节点的链接。双向链表的节点包含:数据项、指向下一节点的链接、指向上一节点的链接。

python中,任何变量都可以引用任何内容,包括None值,此处它表示空链接。通过定义包含两个字段(数据项和对下一节点的引用)的对象,从而定义了单向链表。

链表模型:

首先,如下图中第一个小图所示,我们需要创建一个节点:

class linkNode():
    """
    链表节点类
    """
    def __init__(self,date):
        self.date=date
        self.next=None

详解Python中有关链表操作的理论知识及leetcode面试例题及要点分析_第2张图片
那么,我们应该如何建立该模型呢?

class sigLink():
    """
    self.length   用于记录链表的长度
    self.head     链表的头部
    self.tail     记录链表的尾部
    """
    def __init__(self,item):
        """
    	item 存放该链表的数组
    	"""
        self.length=len(item)
        if self.length<=0:
            return
        i=0
        self.head=linkNode(item[i])
        self.tail=self.head
        i+=1    # 特别注意,此句不能少
        while i<self.length:
            self.tail.next=linkNode(item[i])
            self.tail=self.tail.next
            i+=1

其中,item这一参数可以在实例化时传入一个列表。

遍历链表:

当我们建立好链表以后,我们需要知道链表里面的数据,于是就需要遍历这一过程读取每一个节点的数据内容。这里我们需要一个p标记,就是完成遍历的关键。

def printlink(self):
    """
    正序打印该链表
    """
    if self.head==None:
        print("该链表为空链表!")
    p=self.head
    while p!=None:
        print(p.date,end=" ")
        p=p.next

获取链表的长度:

def getlength(self):
    """
    获取链表的长度
    """
    print("该链表的长度为:", self.length)

在sigLink类中我们已经知道链表的长度,因此只需要返回self.length即可

追加节点:

def linkAppend(self,num):
     """
     在链表尾部追加节点
     """
     self.tail.next=linkNode(num)
     self.tail=self.tail.next
     self.length+=1

先将要插入的数字转换为节点 (linkNode(num)),然后将tail的next域指向linkNode(num),最后再将tail指向 linkNode(num) 即完成了追加这一功能

插入操作:

插入时有四种情况:

  1. 索引值大于链表的长度
  2. 索引值等于0
  3. 索引值刚好等于链表的长度(相当于追加)
  4. 索引值在中间位置
def insertNode(self,index,num):
    """
    在链表中间插入节点
    index:插入节点的序号
    num:插入点的值
    """
    if index>self.length:
        print("index参数超出范围")
        return
    if index==self.length:
        self.linkAppend(num)
        return
    if index==0:
        p=linkNode(num)
        p.next=self.head
        self.head=p
        self.length+=1
        return
    ptemp=self.head
    while index>1:
        ptemp=ptemp.next
        index-=1
    p=linkNode(num)
    p.next=ptemp.next
    ptemp.next=p
    self.length+=1

主调代码:

简单形式的:

a=sigLink([1,2,3,4])
a.printlink()
a.insertNode(2,10)#插入操作
print("\n")
a.printlink()#遍历操作
print("\n")
a.getlength()#获取长度
print("\n")
a.linkAppend(15)#追加节点
a.printlink()

复杂形式的:

a=[]
flag=""
NodeNum=int(input("请输入节点的个数:"))
for i in range(1,NodeNum+1):
    a.append(int(input("您输入的第%d个节点的值为:"%i)))
    
Link=sigLink(a)
number=int(input("请你输入你要执行的次数:"))
i=0#标记次数
while i<number:
    operation=input("请输入你要进行的操作名称:")
    name=flag+str(operation)
    i+=1
    if name=="printlink":
        print("遍历的结果为:")
        Link.printlink()
        print("\n")
    elif name=="getlength":
        Link.getlength()
    elif name=="linkAppend":
        num=int(input("请输入你要追加的数字:"))
        Link.linkAppend(num)
        print("追加成功!")
        print("追加之后遍历的结果为:")
        Link.printlink()
        print("\n")
    elif name=="insertNode":
        Index=int(input("你要索引的位置为::"))
        NodeNum=int(input("你要在%d插入的数字:"%Index))
        Link.insertNode(Index,NodeNum)
        print("插入成功!")
        print("插入之后遍历的结果为:")
        print("\n")
        Link.printlink()
    if name!="printlink" or name!="getlength"or name!="linkAppend" or name!="insertNode":
        print("输入操作名称有误,请重新输入!")
        

while i>=number:
    print("\n")
    print("执行次数已经达到,结束程序!")
    i=i-1

完整代码:

class linkNode():
    """
    链表节点类
    """
    def __init__(self,dat):
        self.dat=dat
        self.next=None
        
class sigLink():
    """
    self.length   用于记录链表的长度
    self.head     链表的头部
    self.tail     记录链表的尾部
    """
    def __init__(self,item):
        """
        item   一位数组,存放改链表的数组
        
        """
        self.length=len(item)
        if self.length<=0:
            return
        i=0
        self.head=linkNode(item[i])
        self.tail=self.head
        i+=1 #此句不能少
        while i<self.length:
            self.tail.next=linkNode(item[i])
            self.tail=self.tail.next
            i+=1
    def printlink(self):
        """
            正序打印该链表
        """
        if self.head==None:
            print("该链表为空链表!")
        p=self.head
        while p!=None:
            print(p.dat,end=" ")
            p=p.next
    def getlength(self):
        """
            获取链表的长度
        """
        print("该链表的长度为:",self.length)
    def linkAppend(self,num):
        """在链表尾部追加节点"""
        self.tail.next=linkNode(num)
        self.tail=self.tail.next
        self.length+=1
    def insertNode(self,index,num):
        """
            在链表中间插入节点
            index:插入节点的序号
            num:插入点的值
        """
        if index>self.length:
            print("index参数超出范围")
            return
        if index==self.length:
            self.linkAppend(num)
            return
        if index==0:
            p=linkNode(num)
            p.next=self.head
            self.head=p
            self.length+=1
            return
        ptemp=self.head
        while index>1:
            ptemp=ptemp.next
            index-=1
        p=linkNode(num)
        p.next=ptemp.next
        ptemp.next=p
        self.length+=1

a=[]
flag=""
NodeNum=int(input("请输入节点的个数:"))
for i in range(1,NodeNum+1):
    a.append(int(input("您输入的第%d个节点的值为:"%i)))
    
Link=sigLink(a)
number=int(input("请你输入你要执行的次数:"))
i=0#标记次数
while i<number:
    operation=input("请输入你要进行的操作名称:")
    name=flag+str(operation)
    i+=1
    if name=="printlink":
        print("遍历的结果为:")
        Link.printlink()
        print("\n")
    elif name=="getlength":
        Link.getlength()
    elif name=="linkAppend":
        num=int(input("请输入你要追加的数字:"))
        Link.linkAppend(num)
        print("追加成功!")
        print("追加之后遍历的结果为:")
        Link.printlink()
        print("\n")
    elif name=="insertNode":
        Index=int(input("你要索引的位置为::"))
        NodeNum=int(input("你要在%d插入的数字:"%Index))
        Link.insertNode(Index,NodeNum)
        print("插入成功!")
        print("插入之后遍历的结果为:")
        print("\n")
        Link.printlink()
    if name!="printlink" or name!="getlength"or name!="linkAppend" or name!="insertNode":
        print("输入操作名称有误,请重新输入!")
        

while i>=number:
    print("\n")
    print("执行次数已经达到,结束程序!")
    i=i-1

部分参考博客:

[1]. python实现链表
[2]. python3实现链表的基础操作

你可能感兴趣的:(多味的LeetCode,数据结构,链表,Leetcode)