数据结构及算法(Python)---单链表

"""
   单链表
   1、节点:
      data: 数据
      next: 下一个节点链接
   2、操作:
      is_empty() 链表是否为空
      length() 链表长度
      travel() 遍历整个链表
      add(item) 链表头部添加元素
      append(item) 链表尾部添加元素
      insert(pos, item) 指定位置添加元素
      remove(item) 删除节点
      search(item) 查找节点是否存在
      index(pos) 获取指定位置上元素
"""


class SingleNode(object):
    """单链表节点"""
    def __init__(self, data):
        """
        节点具有两部分内容,因此具有两个属性
        :param data: 接收创建节点时的数据内容
        """
        self.data = data   # 存放数据
        self.next = None   # 指向下一个节点,初始时为空


class SingleLinkList(object):
    """单链表"""
    def __init__(self, node=None):
        """
        可以创建一个空链表,也可以创建带有一个节点的链表
        :param node: 当创建带有节点的列表时,node用来接收节点数据,使用默认值用来创建空链表
        """
        self.__head = node    # 定义表头,方便操作使用,由于是类内部使用,所以定义为私有变量

    def is_empty(self):
        """
        判断链表是否为空
        :return: False 不为空, True 空
        """
        # 当链表中只有表头时则表示链表时空链表
        if self.__head is None:
            return True
        else:
            return False

    def length(self):
        """
        链表长度:存在两种情况,空表和非空表
        :return: 空表长度为0, 非空时,长度为节点个数(count)
        """
        count = 0            # 记录节点个数
        # 1. 链表非空时,遍历所有节点
        # 定义一个游标用于遍历整个链表,初始时指向表头指向的内容
        cur = self.__head
        # 由于初始时cur指向第一个节点,并且count=0,因此循环的终止条件是cur=None;当然也可以让count初始值为1,终止条件为cur.next=None
        while cur is not None:
            count += 1
            cur = cur.next
        return count
        # 2. 链表为空时,长度为0;由于上面代码同样可以处理空链表的情况,因此空链表不需要特殊处理

    def travel(self):
        """
        遍历整个链表
        :return:
        """
        # 遍历和统计链表长度处理逻辑一样,唯一区别遍历是输入每个节点的data数据,而统计链表长度是记录节点数;
        # 因此可以直接将length()中的代码复制,并将count += 1替换为print(cur.data, end="")即可
        cur = self.__head
        while cur is not None:
            print(cur.data, end=" ")   # 同行输出
            cur = cur.next
        print("")                     # 遍历完后进行换行

    def add(self, data):
        """
        链表头部添加元素:存在空表和非空表两种情况
        :param data: 接收创建节点的数据
        :return:
        """
        # 创建节点
        newNode = SingleNode(data)
        # 1. 非空表情况
        newNode.next = self.__head   # 将新节点的next指向表头指向的节点
        self.__head = newNode        # 将表头指向新节点
        # 2. 空表情况,由于上面代码同样可以处理空链表的情况,因此空链表不需要特殊处理

    def append(self, data):
        """
        链表尾部添加元素:同样存在空表、单个节点链表和多个节点链表情况
        :param data: 接收创建节点的数据
        :return:
        """
        # 创建节点
        newNode = SingleNode(data)
        # 1. 空表情况,等同于链表头部添加
        if self.is_empty():
            self.__head = newNode  # 将表头指向新节点
            return
        # 2. 非空表情况,则需要先找到最后一个节点(参照遍历链表的代码)
        cur = self.__head
        while cur.next is not None:
            cur = cur.next
        cur.next = newNode       # 将最后一个节点的next指向新节点
        # 3. 单个节点链表,由于第2点的代码同样可以处理单节点链表的情况,因此单节点链表不需要特殊处理

    def insert(self, pos, data):
        """
        指定位置添加元素:
        --插入的位置pos存在三种情况 1)链表头部位置pos=0 2)链表尾部位置pos=length() 3)链表中间位置pos=[1,length()-1]
        --链表存在空表、非空表(就上面3中情况)
        --用户输入pos也存在<0或>length()情况
        :param pos: 新节点插入的位置,于列表一样,此处同样以0下标开始
        :param data:  新节点数据
        :return:
        """
        # 1、首先处理异常情况(即:用户输入pos也存在<0或>length()的情况)
        if pos < 0 or pos > self.length():
            print("索引位置越界!")
        # 2. 链表头部位置pos=0,同样适应于空表情况
        elif pos == 0:
            self.add(data)                # 直接调用链表头部插入函数
        # 3. 链表尾部位置pos=length()
        elif pos == self.length():
            self.append(data)             # 直接调用链表尾部插入函数
        # 4. 链表中间位置插入pos=[1,length()-1]
        else:
            # 创建节点
            newNode = SingleNode(data)
            # 定义游标
            cur = self.__head
            # 记录下标位置
            index = 0
            # 当游标移动要插入位置pos的前一个位置时,停止移动
            while index < pos-1:
                index += 1
                cur = cur.next
            newNode.next = cur.next    # 将新节点的next执行pos位置上的节点
            cur.next = newNode         # 将pos前一个位置上的节点的next指向新节点

    def remove(self, data):
        """
        删除节点: 存在情况 1)空表  2)未找到指定节点 3)单节点链表 4)删除节点在链表头部 5)删除节点在链表中间  6)删除节点在链表尾部
        :param data: 要删除的数据
        :return: 删除成功True, 未找到数据False
        """
        # 首先处理删除节点在链表中间的情况,需要使用两个游标进行处理,
        cur = self.__head  # 定义游标(指向当前位置)
        pre = None         # 定义游标(指向上一个节点位置)
        while cur is not None:             # 同样适应空列表 1
            if cur.data == data:
                if cur == self.__head:         # 头节点(同样适应单节点链表) 3,4
                    self.__head = cur.next     # 变成空链表
                else:
                    pre.next = cur.next    # 将上一个节点的next指向当前节点的next(也就是当前节点的下一个节点位置) 5,6
                break
            else:
                pre = cur              # 向后移动
                cur = cur.next
        return False                   # 未找到数据  2

    def search(self, data):
        """
        查找节点是否存在:存在空表的特殊情况
        :param data: 要查找的数据
        :return: 返回查找到的位置索引,未查找到则返回-1
        """
        index = 0                  # 索引下标
        cur = self.__head          # 定义游标
        while cur is not None:     # 循环到cur指向最后一个节点的next,也就是None是结束(同样适用于空表)
            if cur.data == data:   # 查到到数据
                return index       # 返回位置的索引下标
            index += 1
            cur = cur.next
        return -1                  # 未找到数据

    def index(self, pos):
        """
        获取指定位置上的数据:存在空表的特殊情况
        :param pos: 要查找的位置, 索引位置从0开始
        :return: 返回查找到的数据
        """
        index = 0                  # 索引下标
        cur = self.__head          # 定义游标
        while cur is not None:     # 循环到cur指向最后一个节点的next,也就是None是结束(同样适用于空表)
            if index != pos:
                cur = cur.next
                index += 1
            else:
                return cur.data     # 返回指定位置上的数据
        return None                 # 传入的索引位置超出[0~length()-1]范围或链表为空时返回None


if __name__ == '__main__':
    sll = SingleLinkList()
    print("空否:", sll.is_empty())
    print("长度:", sll.length())

    sll.add(1)
    sll.append(3)
    sll.insert(1, 2)
    print("空否:", sll.is_empty())
    print("长度:", sll.length())    # 1,2,3
    sll.travel()

    sll.insert(0, 'ooo')
    sll.insert(-1, 'aaa')
    sll.insert(4, 'bbbb')
    sll.insert(7, 'cccc')
    print("空否:", sll.is_empty())
    print("长度:", sll.length())    # 'ooo',1,2,3,'bbbb'
    sll.travel()

    print(sll.search('bbbb'))   # 5
    print(sll.search('aaaaa'))  # -1

    sll.remove('ooo')
    sll.travel()
    sll.remove('bbbb')
    sll.travel()
    sll.remove('1')
    sll.travel()

    print("长度:", sll.length())
    print('0', sll.index(0))
    print('3', sll.index(3))
    print('-1', sll.index(-1))
    print('10', sll.index(10))

    newNode = SingleNode('hhhhhhh')
    sll2 = SingleLinkList(newNode)
    print("空否:", sll2.is_empty())
    print("长度:", sll2.length())
    sll2.travel()

执行结果:

空否: True
长度: 0
空否: False
长度: 3
1 2 3 
索引位置越界!
索引位置越界!
空否: False
长度: 5
ooo 1 2 3 bbbb 
4
-1
1 2 3 bbbb 
1 2 3 
1 2 3 
长度: 3
0 1
3 None
-1 None
10 None
空否: False
长度: 1
hhhhhhh 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值