python进阶 - 数据结构与算法- 05 双向链表

一、双向链表的结构

1.1 节点的实现

链表中的每一个结点都由前驱结点、数据区和后继结点三部分组成,在Python或者其他语言中没有一个数据类型可以同时储存这三个个数据,因此我们可以定义节点这样一个类,而结点中的前驱结点、数据区和后继结点可以想象成该类的三个属性。
双向链表的结构

在定义一个新的节点时,我们没有办法确定该结点的前驱结点和后继结点,因此我们可以先将其设置为空,当有下一个节点时,在重新对其赋值。

        class Node(object):
              """双向链表的节点"""
		    def __init__(self,item,):
		    
		        #item存放的数据区域
		        self.item = item
		        
		        #prev存放前驱结点的标识
				self.prev = None
				
		        #next存放下一个节点的标识
		        self.next = None

1.2 双向链表的操作

is_empty() 链表是否为空
length() 链表长度
travel() 遍历整个链表
append(item) 链表尾部添加元素
add(item) 链表头部添加元素
insert(pos, item) 指定位置添加元素
search(item) 查找节点是否存在
remove(item) 删除节点

1.3 单链表的操作实现

1.3.1 判断双向链表是否为空

如果双向链表为空,则其首结点为空(self.__head = None);如果双向链表不为空,则其首结点不为空(self.__head = node)。

  class Node(object):
    	"""双向链表的节点"""
	    def __init__(self,item):
	        self.item = item
	        self.prev = None
	        self.next = None

  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	
	    def is_empty(self):
	        """单链表是否为空"""
	        # if self.__head == None:
	        #    return True
	        # return False
	        return self.__head == None

node = Node(100)
d = DoubleLinkList(node)
print(d.is_empty())

1.3.2 双向链表的长度

length()方法
定义一个游标cur,让cur从头指针head出发直到遍历到为指针None
定义一个计数变量count,cur移动一次,count就加1

  class Node(object):
    	"""双向链表的节点"""
	    def __init__(self,item):
	        self.item = item
	        self.prev = None
	        self.next = None

  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
	    def length(self):
	        """链表长度"""
	        count = 0
	        cur = self.__head

	        while cur != None:
	            count += 1
	            cur = cur.next
	        return count

node = Node(100)
d = DoubleLinkList(node)
print(d.length())

1.3.3 遍历双向链表

遍历链表和求链表长度的思想基本一致,唯一不同的就是我们不需要计数变量但每循环一次,我们就需要打印该节点的数据

  class Node(object):
    	"""双向链表的节点"""
	    def __init__(self,item):
	        self.item = item
	        self.prev = None
	        self.next = None

  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
	    def travel(self) :
	        """遍历整个链表"""
	        cur = self.__head
	
	        while cur != None:
	            #打印节点中的数据
	            print(cur.item,end = ' ')
	            cur = cur.next

node = Node(100)
d = DoubleLinkList(node)
d.travel()

1.3.4 向双向链表尾部添加元素

append()方法
向链表尾部添加节点时,需要进行两个操作:
1.创建一个新的节点 node = SingleNode(item)
2.遍历到最后一个节点,令其的next属性等于新的节点cur.next == node,新节点的prev属性等于当前节点node.prev = cur
注意,当链表为空时,self.__head = None,而None类型没有next属性

  class SingleNode(object):
	    	"""单链表的节点"""
		    def __init__(self,item):
		        self.item = item
		        self.next = None
	
  class SingleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
	    def append(self,item):
	        """链表尾部添加元素"""
	        node = Node(item)
	
	        #空链表的情况
	        if self.is_empty():
	           self.__head = node
	        else:
	            cur = self.__head
	            #遍历找到最后一个节点
	            while cur.next != None:
	                    #添加新的节点
	                cur = cur.next
	            cur.next = node
	            node.prev = cur
     
  d = DoubleLinkList()
  d.append(200)
  d.append(220)
  d.append(890)
  d.travel()

1.3.5 链表头部添加元素

add()方法
向链表头部添加节点,需要进行一下三步操作:
1.创建一个新的节点 node = SingleNode(item)
2.令原先的首指针等于新节点的下一个节点标识node.next = self.__head,原先的首节点前驱结点是新节点,self.__head.prev = node
3.令新节点等于首指针 self.__head = node
4.考虑空链表的情况

  class Node(object):
	    	"""双向链表的节点"""
		    def __init__(self,item):
		        self.item = item
		        self.prev = None
		        self.next = None
	
  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
	    def add(self,item):
	        """链表头部添加元素"""
	        node = Node(item)
	        if self.is_empty():
	            self.__head = node
	        else:
	            node.next = self.__head
	            self.__head.prev = node
	            self.__head =node
     
  d = DoubleLinkList()
  d.add(200)
  d.append(220)
  d.append(890)
  d.add(67)
  d.travel()

1.3.6 insert(pos, item) 指定位置添加元素

insert()方法的实现
在指定位置插入节点需要进行以下三步操作
1.通过循环找到指定插入位置的前一个节点
count < pos-1
2.将当前节点下一个节点赋值给新节点的下一个节点标识node.next = cur.next;新节点的前驱结点为当前节点 node.pre = cur;将新节点赋值给当前节点下一个节点的前驱结点cur.next.prev = node;当前节点的后继结点为新节点cur.next = node

需要考虑特殊两种情况,当pos <= 0 时,头部插入add();当pos > length()时,尾部插入append()

  class Node(object):
	    	"""双向链表的节点"""
		    def __init__(self,item):
		        self.item = item
		        self.prev = None
		        self.next = None
	
  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
        def  insert(self,pos,item):
	        node = Node(item)
	        if pos <= 0:
	            #头部插入
	            self.add(item)
	        elif pos > self.length()-1:
	            #尾部插入
	            self.append(item)
	        else:
	            count = 0
	            cur = self.__head
	            while count < pos-1:
	                count += 1
	                cur = cur.next
	                #循环结束,定位到要插入节点的前一个节点
	            node.next = cur.next
	            node.prev = cur
	            cur.next = node
	            cur.next.prev = node
     
  d = DoubleLinkList()
  d.append(200)
  d.append(220)
  d.append(890)
  d.insert(2,67)
  d.travel()

注意:节点位置从0开始。

1.3.7 查找节点是否存在

遍历链表,如果当前节点的item值等于所查找的item值,则返回True,如果不是则游标后移。如果遍历完整个链表仍没有找到,则返回False。

      class Node(object):
	    	"""双向链表的节点"""
		    def __init__(self,item):
		        self.item = item
		        self.prev = None
		        self.next = None
	
  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
        def search(self,item):

	        cur = self.__head
	        while cur != None:
	            if cur.item == item:
	                return True
	            cur = cur.next
	        return False
	                 
  d = DoubleLinkList()
  d.append(200)
  d.append(220)
  d.append(890)
  d.insert(2,67)
  d.travel()
  print(d.search(200))

1.3.8 删除指定元素

remove()方法的实现
删除指定节点,具体操作如下
1.遍历链表,判断cur.item == item
2.如果相等,则令pre.next= cur.next
3.不相等则指针继续后移 pre= cur cur= cur.next

注意特殊情况
a.删除头节点且链表长度为1;
b.删除头节点且链表长度不为1;
c.删除尾节点

  class Node(object):
	    	"""双向链表的节点"""
		    def __init__(self,item):
		        self.item = item
		        self.prev = None
		        self.next = None
	
  class DoubleLinkList(object):

	    def __init__(self,node = None):
	        # 向参数传递默认值,如果没有向该参数传递实参,则该参数等于默认值
	        # 否则,等于实参值
	        self.__head = node
	        
	    def remove(self,item):
	       #空链表
            if self.is_empty():
	            return
			#非空链表
	        cur = self.__head
	        if cur.item == item:
	            #头节点是要删除的节点,且链表长度不为1
	            if cur.next != None:
	                self.__head = cur.next
	            else:
	                #删除头结点,且链表长度为1
	                self.__head = None
	        else:
	            while cur != None:
	                if cur.item == item:
	                    #删除中间节点
	                    if cur.next != None:
	                        cur.prev.next = cur.next
	                        cur.next.prev = cur.prev
	                        break
	                    else:
	                        #删除尾节点
	                        cur.prev.next = None
	                        break
	                else:
	                    cur = cur.next 
       
  d = DoubleLinkList()
  d.append(200)
  d.append(220)
  d.append(890)
  d.insert(2,67)
  d.travel()
  print()
  d.remove(200)
  d.travel()

def remove(self, item):
    """删除指定元素"""
    if self.is_empty():
        return

    cur = self.__head
    if cur.item == item:
        # 头节点是要删除的节点,且链表长度不为1
        if cur.next != None:
            self.__head = cur.next
        else:
            # 删除头结点,且链表长度为1
            self.__head = None
    else:
        while cur != None:
            if cur.item == item:
                # 删除中间节点或尾节点
                cur.prev.next = cur.next
                if cur.next != None:
                  #删除的是中间节点时,需要修改前驱结点 
                    cur.next.prev = cur.prev
                break
            else:
                cur = cur.next
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值