数据结构——链表(三)

链表

链表是有0个或多个相互间有连接的结点构成的。每个结点包含数据区和链接取(指针区)

1. 单链表

1.1 单链表的特性
  • 这是通过单链表构成的一个数组Li = [200,400,600]]
  • 每个结点的指针区指向下一个节点
  • 最后一个节点指向None
  • 链表有一个头指针
    在这里插入图片描述
1.2 单链表支持的操作

链表由结点构成,在建链表前,新建结点类
结点类

class Node(object):
    def __init__(self,item):
        self.element = item
        self.next = None

链表类

class Single_link_list(object):
    def __init__(self,node=None):
        self.__head = node
  1. 是否为空链表 链表的头结点是否为空
    def is_empty(self):
        return self.__head == None
  1. 链表长度 遍历链表计算长度
   def length(self):
       cursor = self.__head # 记录当前指针所在位置
       count = 0 # 记录元素个数
       while cursor != None:# cursor不为空,一直计数,指针向后移动
           count += 1
           cursor = cursor.next
       return count
  1. 链表头部添加元素
    在现有链表[20,40]的头部插入一个值为60的结点
    在这里插入图片描述
    先让node的指针指向head指向的区域,然后让head指向node
    在这里插入图片描述
    代码
def insert_head(self, item):  # 在头部插入
    node = Node(item)
    node.next = self.__head
    self.__head = node
  1. 链表尾部加入元素
    如果是空链表,直接让head指针指向新建的结点。否则,找到链表的尾部结点,让尾部结点指向新建的结点
def append(self, item):
    '''
    在尾部插入
    :param item: 待插入的数
    :return: None
    '''
    node = Node(item)

    # 若链表为空,cursor无next属性
    if self.is_empty():
        self.__head = node
        return
    # 链表不为空,遍历到尾部,尾部指针指向新建的节点
    cursor = self.__head
    while cursor.next != None:  # 找尾部结点
        cursor = cursor.next
    cursor.next = node
  1. 链表任意位置插入元素 insert
    在头部和尾部插入参考上面的
    在现有链表[60,20,40]的中间插入一个值为80的结点,新链表为[60,20,80,40]。先找到插入的位置,及cursor指向的位置,然后node.next指向cursor,在让cursor的前一个结点指向node.
    这里有两个问题:
  • 怎么找到插入的位置?
  • cursor的前一个结点怎么表示
    在这里插入图片描述
    关于插入的位置pos?
    定义记录位置的变量count及初始指向链表部的指针cursor=self.__head。count累加,cursor向后移动,当cout==pos时,cursor也移动到了待插入的位置
    cursor的前一个结点表示
    定义指针pre=None,cursor在移向下一个位置前,将cursor的值赋给pre,这样,pre和cursor间始终相隔一个结点。
    在这里插入图片描述
    代码实现
def insert(self, pos, item):
    '''

    :param pos: 插入位置
    :param item: 插入元素
    :return: None
    '''
    if pos < 1:  # 位置<1,从头部插入
        self.insert_head(item)
        return
    if pos >= self.length():# 从尾部插入
        self.append(item)
        return
    node = Node(item)
    count = 0 # 记录当前指针指向的位置
    pre = None # 初始化前驱结点
    cursor = self.__head # 初始化当前结点
    while count < pos:
        # 还没找到时,指针一直向后移动
        pre = cursor
        cursor = cursor.next
        count += 1
    # 找到位置后,改变node指针指向
    node.next = cursor
    pre.next = node
  1. 删除元素

头结点删除
现有链表[60,20,80,40],删除60这个元素,怎么操作?

  • 直接让头结点指向当前结点的下一个结点
    在这里插入图片描述
    非头结点删除
    现有链表[60,20,80,40],删除80这个元素,怎么操作?
  • 找到80这个结点,cursor指向80这个结点,然后让结点20的指针指向结点80的后面一个结点40。
  • 没找到时,cursor和pre一直向后移动
  • 向后移动的终止条件是,找到了待删除的元素或者cursor移动到了链表外

在这里插入图片描述

    def remove(self,item):
        '''
        删除元素
        :param item:
        :return:
        '''

        if self.is_empty():
            #空链表
            return
        # 需要有前后指针,pre.next = cursor
        pre = None
        cursor = self.__head
        while cursor != None:
            if cursor.element == item:
                if pre:  # 删除的不是头结点
                        pre.next = cursor.next
                else:# 删掉的是头结点
                        self.__head = cursor.next
                return
            else:
                pre = cursor
                cursor = cursor.next
  1. 查找链表
def search(self, item):
    if self.is_empty():
        return False
    cursor = self.__head
    while cursor != None:
        if cursor.element == item:
            return True
        else:
            cursor = cursor.next
    return False
  1. 遍历链表
def travel(self):
    '''
    遍历链表,输出
    :return: None
    '''
    # if self.is_empty():
    #     return
    cursor = self.__head
    while cursor != None:
        print(cursor.element, end=' ')
        cursor = cursor.next
    print()

2. 双向链表

2.1 双向链表的特性
  • 这是通过单链表构成的一个数组Li = [20,40,60]]
  • 每个结点有两个指针:前驱指针和后继指针,前驱指针指向前一个结点,后继指针指向下一个节点
  • 第一个结点的前驱指针指向None,最后一个节点后继指针指向None
  • 链表有一个头指针
  • 与单向链表相比,双向链表多了一个前驱指针
    在这里插入图片描述
2.2 单链表支持的操作

与单向链表相比,双向链表多了一个前驱指针。在基本操作实现上,部分双向链表的操作与单向链表操作相同

  • 判断是否为空链表,只需判断头结点是否为空即可,这与单链表代码实现相同
  • 计算链表长度、查找链表、遍历链表都只需后继指针向后移动即可,不涉及到前驱指针的操作,所以,这些也与单链表代码实现相同
    在这里插入图片描述
  • 定义结点类
class Node(object):
    '''
    双向链表,每个节点有一个前驱指针,一个后继指针,一个元素区
    '''
    def __init__(self,item):
        self.element = item
        self.next = None
        self.pre = None
  1. 链表头部添加元素
  • 空链表头部添加
    与单向链表相同
  • 非空链表头部添加
    在这里插入图片描述
def insert_head(self, item):  # 在头部插入
    node = Node(item)
    if self.is_empty():
        self.__head = node
    else:
        node.next = self.__head
        self.__head.pre = node
        self.__head = node
  1. 在尾部添加
  • 链表为空,与单向链表相同,直接将头指针指向新建结点
  • 非空链表尾部添加。原始链表[20,40,60],在尾部添加后,变为[20,40,60,80]
    在这里插入图片描述
def append(self, item):
    '''
    在尾部插入
    :param item: 待插入的数
    :return: None
    '''
    node = Node(item)

    # 若链表为空,cursor无next属性
    if self.is_empty():
        self.__head = node
        return
    # 链表不为空,遍历到尾部,尾部指针指向新建的节点
    cursor = self.__head
    while cursor.next != None:
        cursor = cursor.next
    cursor.next = node  # 指向后面
    node.pre = cursor  # 指向前面
  1. 在任意位置添加
  • 在头部和尾部插入参考insert_head和append
  • 在中间部分插入,还需要考虑前驱指针变化
    插入时,先保留原有的连接,将新建结点链接到该插入的位置,然后改变原有链接
    1). 新建结点的前驱指向当前结点的前一个结点node.pre = cursor.pre
    2). 新建结点的后继指向当前结点node.next = cursor
    3). 当前结点的前一个结点的后继指向新建结点cursor.pre.next = node
    4). 当前结点的前驱指向新建结点cursor.pre= node
    在这里插入图片描述
    代码实现
def insert(self, pos, item):
    '''

    :param pos: 插入位置
    :param item: 插入元素
    :return: None
    '''
    if pos < 1:  # 位置<1,从头部插入
        self.insert_head(item)
        return
    if pos >= self.length():
        self.append(item)
        return
    node = Node(item)
    count = 0
    # pre = None# 不需要pre
    cursor = self.__head
    while count < pos:
        count += 1
        cursor = cursor.next

    node.next = cursor
    node.pre = cursor.pre
    cursor.pre.next = node
    cursor.pre = node
  1. 删除链表元素
  • 删除的是头结点,self.__head = cursor.next, self.__head.pre = None
  • 一般情况删除的示意图
    在这里插入图片描述
    找出待删除的元素,需要遍历链表。遍历结束的条件是,找到元素或者找到了最后一个元素。如果是找到了元素,按图示操作即可,如果是跳出了循环,还有最后一个元素没有比较,需在循环外比较。
    def remove(self,item):
        '''
        删除元素
        :param item:
        :return:
        '''

        if self.is_empty():
            #空链表
            return
        # 需要有前后指针,pre.next = cursor
        cursor = self.__head
        while cursor.next != None:
            if cursor.element == item:
                if cursor.pre:# 删除的不是头结点
                   cursor.pre.next = cursor.next
                   cursor.next.pre = cursor.pre
                else:#删除的是头结点
                    self.__head = cursor.next
                    self.__head.pre = None

                return
            else:
                cursor = cursor.next
        if cursor.element == item: # 待删除元素与最后一个元素比较
            cursor.pre.next = None

3. 单向循环链表

3.1 单向循环链表的特性

与单向链表相比,每个结点也是包含数据区和指针区。不同的是尾结点的指针指向的是头结点
在这里插入图片描述

3.2 单向循环链表的基本操作

由于单向循环链表的最后一个结点的指针指向第一个结点,所以遍历链表的循环条件是cursor.next != self.__head

  1. 结点定义与单向链表相同
class Node(object):
    def __init__(self,item):
        self.element = item
        self.next = None
  1. 单向链表初始化
    用非空结点初始化时,让结点的next指针指向自身
class Single_cycle_link_list(object):
    def __init__(self,node=None):
        self.__head = node
        if node:
            node.next = node
  1. 是否为空的判断与单向列链表相同
  2. 求链表长度
def length(self):
    cursor = self.__head
    if self.is_empty():
        return 0
    count = 1
    while cursor.next != self.__head:  # cursor不指向队首,一直计数,指针向后移动
        count += 1
        cursor = cursor.next
    return count
  1. 在头部插入元素
def insert_head(self, item):  # 在头部插入
    node = Node(item)
    if self.is_empty():
        self.__head = node
        if node:
            node.next = node
    else:
        node.next = self.__head
        self.__head.pre = node
        self.__head = node
  1. 在尾部插入
def append(self, item):
    '''
    在尾部插入
    :param item: 待插入的数
    :return: None
    '''
    node = Node(item)

    # 若链表为空,cursor无next属性
    if self.is_empty():
        self.__head = node
        return
    # 链表不为空,遍历到尾部,尾部指针指向新建的节点
    cursor = self.__head
    while cursor.next != None:
        cursor = cursor.next
    cursor.next = node  # 指向后面
    node.pre = cursor  # 指向前面
  1. 在任意位置插入————与单向链表相同
  2. 删除元素
  • 链表是否为空
  • 删除的是否是头结点
  • 链表最后一个元素的处理
    def remove(self,item):
        '''
        删除元素
        :param item:
        :return:
        '''

        if self.is_empty():
            #空链表
            return
        # 需要有前后指针,pre.next = cursor
        cursor = self.__head
        while cursor.next != None:
            if cursor.element == item:
                if cursor.pre:# 删除的不是头结点
                   cursor.pre.next = cursor.next
                   cursor.next.pre = cursor.pre
                else:#删除的是头结点
                    self.__head = cursor.next
                    self.__head.pre = None

                return
            else:
                cursor = cursor.next
        if cursor.element == item:
            cursor.pre.next = None

附:
python中的变量表示的是数据的地址,当交换变量值是,实际是交换变量指向的区域
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值