链表的python实现

使用python中的基本数据类型实现–链表

内容来自读书笔记《数据结构与算法的python描述》

class LNode(object):
    """链表的节点类"""

    def __init__(self, val, next_=None):
    # 经典链表的节点具有连部分内容--<数据>--<next指针>
        self.val = val
        self.next = next_


def testcase_LNode():
    # 实现单链表,并将其数据一次打印出来
    rootNode = LNode(1)
    root = rootNode
    for i in range(2, 11):
        root.next = LNode(i)
        root = root.next

    root = rootNode
    while root is not None:
        print(root.val)
        root = root.next


class LinkedListUnderflow(ValueError):
    pass


class LList(object):
	"""定义单链表类"""
    def __init__(self):
        # _head对应当前节点
        self._head = None

    def is_empty(self):
        return self._head is None

    # 前端插入
    def prepend(self, val):
        # 实例化一个新的节点LNode,将新节点的next指向当前节点,将当前节点设置成为新节点
        newLNode = LNode(val, self._head)
        self._head = newLNode

    def pop(self):
        # 删除元素当前头元素
        if self._head is None:
            raise LinkedListUnderflow("in pop")
        e = self._head.val
        # 指针指向下下个
        self._head = self._head.next
        return e

    # 后端插入
    def append(self, val):
        newNode = LNode(val)
        if self._head is None:
            # 空链表生成新的节点
            self._head = newNode
            return
        p = self._head
        # 循环遍历到整个链表的末尾
        while p.next is not None:
            p = p.next
        # 在末尾节点添加一个新的节点
        p.next = newNode

    def pop_last(self):
        if self._head is None:
            raise LinkedListUnderflow('in pop_last')
        p = self._head
        # 如果当前节点的下一个节点是空,当前链表只含有一个节点
        if p.next is None:
            # 获取当前节点的值
            e = p.val
            # 将当前节点设置成空
            self._head = None
            return e
        # 循环 判断当前节点的下一下一节点是否非空
        while p.next.next is not None:
            # 如果非空的话就向下遍历
            # 如果为空,那么当前节点就是倒数第二节点,也就是删除末尾后的新末尾节点,不再遍历
            p = p.next
        # 跳出循环后,将当前节点的下一节点(末节点)的值取出
        e = p.next.val
        # 将末节点设置成空
        p.next = None
        return e

    def find(self, pred):
        p = self._head
        while p is not None:
            if pred(p.val):
                return p.val
            p = p.next

    def printall(self):
        p = self._head
        while p is not None:
            # 输出当前节点的值,不换行
            print(p.val, end='')
            # 如果当前节点的下一个节点非空
            if p.next is not None:
                # 输出一个逗号,不换行
                print(', ', end='')
            p = p.next
        # 循环结束输出换行
        print('')

    # 链表的遍历操作 ,proc是一个针对表内所有节点的值的操作
    # 例如 lambda x: print(f'val is {x}')
    def for_each(self, proc):
        p = self._head
        while p is not None:
            proc(p.val)
            p = p.next

    def values(self):
        # 生成器的方式返回链表中的值
        p = self._head
        while p is not None:
            yield p.val
            p = p.next

    def find_all(self, pred):
        # 遍历筛选,返回生成器
        p = self._head
        while p is not None:
            if pred(p.val):
                print(p.val)
                yield p.val
            p = p.next

    def rev(self):
        # 反转,意味着将旧的链表从头到尾拿出来,形成一个新的链表
        p = None
        while self._head is not None:  # 只要当前节点不为空
            q = self._head  # 获取当前节点
            # 将当前节点设置成为下一个节点
            self._head = q.next
            # 将取出的原头节点的下一节点设置成p
            q.next = p
            # 将操作完成的q赋值给p
            p = q
        self._head = p

    def sort_insert_1(self):
        """定义经典单链表的排序方式"""
        if self._head is None:  # 空表
            return
            # 取当前节点的下一节点为cur
        cur = self._head.next
        while cur is not None:  # 以cur非空为条件进行循环
            x = cur.val  # 将cur的值赋给x [对于p来说,是下一节点的值赋值给x]
            p = self._head  # 将当前节点赋给p
            print('p-self.header', p.val)
            while p is not cur and p.val <= x:  # 以p为非cur并且p的值<=x[下一节点的值]为条件循环   目的是跳过正常顺序的元素
                # p指针后移
                p = p.next
            # 如果不满足上述条件,那么意味着前者比后者大
            while p is not cur:  # 以p不是cur为条件进行循环   调整元素位置
                y = p.val  # 获取此时p的值
                p.val = x  # 将小的值x赋值到p的val上
                x = y  # 将大的值赋值给x  以新x进入判断
                p = p.next
            cur.val = x
            cur = cur.next
            # 每调换一次顺序,p指针滚回为首指针,重新扫描

    def sort_insert_2(self):
        """第二种插入排序,1是改变值,2是将乱序的节点拆下来,放到有序的节点中"""
        p = self._head  # 获取当前节点
        if p is None or p.next is None:
            # 如果是空表或者只有一个元素,那么本来就是有序的
            return
        rem = p.next
        p.next = None
        while rem is not None:
            p = self._head
            q = None
            while p is not None and p.val <= rem.val:
                q = p
                p = p.next
                if q is None:
                    self._head = rem
                else:
                    q.next = rem
                q = rem
                rem = rem.next
                q.next = p


# 具有头节点指向尾节点的链表 (变形一)
class LinkListHaveRear(LList):
    def __init__(self):
        super(LinkListHaveRear, self).__init__()
        self._rear = None

    def prepend(self, val):
        # 判断空表
        if self._head is None:
            self._head = LNode(val, self._head)
            self._rear = self._head
        else:
            self._head = LNode(val, self._head)

    def append(self, val):
        newNode = LNode(val)
        # 判断空表
        if self._head is None:
            self._head = newNode
            self._rear = self._head
        else:
            self._rear.next = newNode
            self._rear = newNode

    def pop_last(self):
        # 判断空表
        if self._head is None:
            raise LinkedListUnderflow('in pop_last')
        p = self._head
        # 判断表中只有一个元素的情况
        if p.next is None:
            e = p.val
            self._head = None
            return e
        while p.next.next is not None:
            p = p.next
        e = p.next.val
        p.next = None
        return e


# 环状链表(变形二)
class CircleLinkList(object):
    def __init__(self):
        self._rear = None

    def is_empty(self):
        return self._rear is None

    def prepend(self, val):
        p = LNode(val)
        if self._rear is None:  # 空表
            p.next = p  # 自己指向自己
            self._rear = p
        else:
            # a->b  self._rear 现在是a next 是b 在 a和b中间加个p a->p->b
            p.next = self._rear.next
            self._rear.next = p

    def append(self, val):
        # 尾端插入 都是环了,所以和首段插入没差别
        # 先在首部插入一个新节点
        self.prepend(val)
        # 此时首节点就变成了新节点,那么需要改变指针,将这个新节点的下一个节点设置成为首节点
        self._rear = self._rear.next

    # 弹出前一个
    def pop(self):
        # 空表
        if self._rear is None:
            raise LinkedListUnderflow('in pop of CircleLinkList')
        # 获取首节点的下一个节点
        p = self._rear.next
        if self._rear is p:  # 判断这个表中是否只有一个节点
            self._rear = None
        else:
            self._rear.next = p.next
        return p.val

    # 弹出后一个
    def pop_last(self):
        # 空表
        if self._rear is None:
            raise LinkedListUnderflow('in pop_last CircleLinkList')
        # 获取当前节点的下一节点
        p = self._rear.next
        # 判断是否只有一个节点
        if self._rear is p:
            e = p.val
            self._rear = None
            return e
        else:
            while True:
                # 如果p的下一个的下一个节点是首节点那么意味着p的下一个节点因该被pop掉
                if p.next.next is self._rear:
                    # 获取该被pop掉的那个节点
                    e = p.next.val
                    # p节点的下一个节点设为首节点,这样就把中间那个节点给隔掉了
                    p.next = self._rear
                    return e
                p = p.next

    def printall(self):
        if self.is_empty():
            return
        p = self._rear.next
        while True:
            print(p.val, end='')
            if p is self._rear:
                print('')
                break
            p = p.next
            print('->', end='')


if __name__ == '__main__':
    # mlist_1 = LList()
    # for i in range(10):
    #     # 首端插入
    #     mlist_1.prepend(i)
    # for i in range(11, 20):
    #     # 尾端插入
    #     mlist_1.append(i)
    # 打印 方法测试
    # mlist_1.pop_last()
    # mlist_1.pop()
    # r = mlist_1.find(lambda x: x == 14)
    # print(r)
    # mlist_1.printall()

    # 遍历操作测试
    # mlist_1.for_each(lambda x: print(f'val is {x}'))
    # 生成器测试
    # r = mlist_1.values()
    # print(next(r))
    # print(next(r))
    # print(next(r))
    # r = [ i for i in mlist_1.values()]
    # print(r)
    # find_all 测试
    # r = mlist_1.find_all(lambda x: x % 2 == 0)
    # print(list(r))
    # mlist_2 = LinkListHaveRear()
    # mlist_2.prepend(100)
    # for i in range(10):
    #     mlist_2.append(i)
    # mlist_2.printall()

    # mlist_3 = CircleLinkList()
    # mlist_3.prepend(5),
    # mlist_3.prepend(4)
    # mlist_3.printall()
    # for i in range(6, 10):
    #     mlist_3.append(i)
    # mlist_3.printall()
    # mlist_3.pop()
    # mlist_3.pop_last()
    # mlist_3.printall()
    ms_1 = LList()
    ms_1.printall()
    ms_1.append(1)
    ms_1.append(2)
    ms_1.append(5)
    ms_1.append(4)
    ms_1.append(3)
    ms_1.printall()
    # ms_1.sort_insert_1()
    ms_1.sort_insert_2()
    ms_1.printall()

链表的排序使用到插入排序的内容

# 插入排序
def ins_sort(lst):
    for i in range(1, len(lst)):
        x = lst[i]  # 从第二个元素开始辨遍历,获取当前值          值 x
        j = i  # 获取当前位置[判断点]                         位置 j
        while j > 0 and lst[j - 1] > x:  # 循条件           列表中还有元素而且当前值<前一个值   [后面比前面小]
            lst[j] = lst[j - 1]  # 执行交换                 将大的[前面]赋值给当前[后面]
            j -= 1  # 判断点j向前移动                        上述的判断完成后,继续判断是否前面还有比x大的元素,然后再执行[向后]赋值
        lst[j] = x  # 最终循环结束,将x值放在应该它存在的位置      正确位置[前者<=x<后者]


if __name__ == '__main__':
    a = [1, 8, 3, 5, 5, 6, 3, 3, 7, 9, 0]
    ins_sort(a)
    print(a)


约瑟夫环问题

"""
约瑟夫环的问题   使用顺序表解决
n 个人坐一圈
从第k个开始报数
报到第m个数的人退出
"""


def josephus_python_list(n, k, m):
    """
    使用python的list方式解决
    不存在改变表结构
    人走了,就将数置为0[人走椅子留下]
    :param n:
    :param k:
    :param m:
    :return:
    """
    people = list(range(1, n + 1))
    i = k - 1
    for num in range(n):
        count = 0
        while count < m:
            if people[i] > 0:
                count += 1
            if count == m:
                print(people[i], end='')
                people[i] = 0
            i = (i + 1) % n
        if num < n - 1:
            print(", ", end='')
        else:
            print('')
    return


def josephus_python_list2(n, k, m):
    people = list(range(1, n + 1))
    num, i = n, k - 1
    for num in range(n, 0, -1):
        i = (i + m - 1 ) % num
        print(people.pop(i), end=(", " if num > 1 else "\n"))
    return


if __name__ == '__main__':
    josephus_python_list(10, 2, 7)
    josephus_python_list2(10, 2, 7)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值