Python单链表实现list一样的功能

Python单链表实现list一样的功能

知识点:链表,魔法方法,迭代器,排序,内置函数
# 定义链表
class LinkedList():
    class Node():
        def __init__(self, item):
            self.item = item
            self.next = None

    def __init__(self):
        self.head = None
        self.__length = 0

    def headadd(self, item):
        """头部插入数据,list中没有的方法
        """
        new_node = self.Node(item)
        if self.head == None:
            self.head = new_node
        else:
            new_node.next = self.head
            self.head = new_node

    def append(self, item):
        p = self.head
        new_node = self.Node(item)
        if p == None:
            self.head = new_node
            self.__length += 1
            return
        while p:
            if p.next == None:
                p.next = new_node
                self.__length += 1
                return
            p = p.next

    def insert(self, index, item):  # 默认头部插入
        if index >= self.__length:  # 尾部插入
            self.append(item)
            return

        elif index <= 0:  # 头部插入
            new_node = self.Node(item)
            new_node.next = self.head
            self.head = new_node

        else:  # 中间插入
            new_node = self.Node(item)
            p = self.head
            count = 0
            while p:
                if count == index - 1:
                    new_node.next = p.next
                    p.next = new_node
                    break
                p = p.next
                count += 1
        # 链表长度增加
        self.__length += 1

    def pop(self, index):
        if index < -self.__length or index >= self.__length:
            raise IndexError("pop index out of range")

        elif index == 0 or index == -self.__length:  # 去掉首位
            item = self.head.item
            self.head = self.head.next
            self.__length -= 1
            return item

        else:
            if index < 0:  # 负下标情况,转换成正下标
                index = self.__length + index
            p = self.head
            count = 0
            while p:
                if count == index - 1:
                    item = p.next.item
                    p.next = p.next.next
                    self.__length -= 1
                    return item
                else:
                    p = p.next
                    count += 1

    def sort(self, start=None, stop=None, reverse=False):
        # 排序 ;快速排序;为了方便使用下标索引进行排序
        if start == None:
            start = 0
        if stop == None:
            stop = self.__length-1
        left = start
        right = stop

        if right <= left:
            return

        mid = self[left]
        while right > left:
            while self[right] >= mid and right>left:
                right -= 1
            if right>left:
                self[left] = self[right] # 右边移动到左边
            else:
                self[right] = mid
                break

            while self[left] <= mid and left < right:
                left += 1
            if left < right:
                self[right] = self[left] # 左边移动到右边
            else:
                self[left] = mid
                break
        self.sort(start, left-1) # 递归对左边排序
        self.sort(right+1, stop) # 递归对右边排序

        if reverse:
            p = self.head
            temp = None
            while p:
                next = p.next
                p.next = temp
                temp = p
                p = next
            self.head = temp

    def __getitem__(self, index):
        """当使用[]索引获取对象时的行为,例如 a[1]
        """
        if isinstance(index, int):  # 当传入的是 int 类型
            if index >= self.__length or index < -self.__length:
                raise IndexError("index out of range")

            else:
                p = self.head
                if index < 0:
                    index = self.__length + index
                for i in range(index):
                    p = p.next
                return p.item
        elif isinstance(index, slice):  # 当传入的是 slice对象,即切片 例如 a[1:4:2] 左闭右开
            """ slice对象有三个属性,start,stop,step
            """
            # 传入参数处理
            start = index.start if index.start != None else 0
            stop = index.stop if index.stop != None else self.__length
            step = index.step if index.step != None else 1

            if not (isinstance(start, int) and isinstance(stop, int) and isinstance(step, int)):
                raise TypeError('type of index error;please input int type.')

            ## 将负小标转为正下标处理
            if start < 0:
                start = 0 if start <= -self.__length else self.__length + start
            if stop < 0:
                stop = 0 if stop <= -self.__length else self.__length + stop

            if step < 0 and start >= stop: # 当step <0 时代表从后向前切片
                start, stop = stop, start

            p = self.head
            new_list = LinkedList()
            count = 0


            while p:
                new_node = self.Node(p.item)
                if start <= count < stop:  # 左闭右开
                    if start == count:
                        new_p = new_list.head = new_node

                    else:
                        # new_p = new_p.next = p
                        if step > 0:
                            # 当step >0 时,使用尾部插入,new_p 即当前尾部
                            new_p.next = new_node
                            new_p = new_p.next
                        else:
                            # 当step < 0时,使用头插入
                            new_node.next = new_list.head
                            new_list.head = new_node
                elif count >= stop:
                    return new_list

                for i in range(abs(step)):
                    p = p.next
                    count += 1

            return new_list


        else:
            raise TypeError("type of index error")

    def __delitem__(self, key):
        """当按照[]下标索引使用del方法删除元素时,触发此函数, 例如 del a[1]
        若 不重写次函数,则会报异常 AttributeError: __delitem__
        """
        if not isinstance(key, int):
            raise TypeError("type of key error")

        if key < - self.__length or key >= self.__length:
            raise IndexError("index out of range")

        self.pop(key)

    def __setitem__(self, index, item):
        """当使用[]索引对元素赋值的行为, 例如 a[0]=2
        """
        if isinstance(index, int):
            if index < -self.__length or index >= self.__length:
                raise IndexError("index out of range")
            else:
                p = self.head
                if index < 0:
                    index = self.__length + index
                for i in range(index):
                    p = p.next
                p.item = item
        else:
            raise Exception("type of index error")

    def __contains__(self, item):
        # 当使用 in 或者not in 判断时的行为; 当已经实现了迭代器时(即重写了__iter__ 与__next__ 两个方法)
        # 此方法可以不用重写
        for each in self:
            if each == item:
                return True
        else:
            return False

    def __add__(self, right_list):
        """ 当调用 + 法的行为, 如果未调用此方法则会报异常(TypeError)
        """
        temp = LinkedList()  # 新建一个单链表
        for each in self:
            temp.append(each)
        for each in right_list:
            temp.append(each)
        return temp

    def __len__(self):
        """当对该对象使用len()函数时触发此函数
        """
        return self.__length

    def __iter__(self):
        """当对该对象使用 iter()函数时触发此函数,返回一个迭代器。实现了迭代器,则可以调用list/tuple/set方法与容器对象进行类型转换。
        与__next__方法搭配使用
        """
        # 必须使用一个指针栈 _p_list , 以免出现指针的引用的重复。当之定义一个变量作为指针时,在for循环嵌套中会与逻辑异常。
        if not hasattr(self, '_p_list'):
            setattr(self, '_p_list', [self.head])
        else:
            self._p_list.append(self.head) # 入栈
        return self

    def __next__(self):
        """当对生成器使用next()方法时触发此函数,与__iter__函数搭配使用,要使用StopIteration异常作为结束条件
        """
        p = self._p_list[-1]
        if p:
            item = p.item
            self._p_list[-1] = p.next
            return item
        else:
            del self._p_list[-1] # 出栈
            raise StopIteration

    def __str__(self):
        """当使用print()打印时的动作
        """
        string = ''
        for each in self:
            string += str(each) + '->'

        return string if string else '->'

# 测试部分功能
if __name__ == '__main__':
    a = LinkedList()
    import random
    r = [random.randint(0, 20) for i in range(10)]
    for i in r:
        a.append(i)
    print('排序测试:')
    print(a)
    a.sort()
    print(a)
    a.sort(reverse=True)
    print(a)

    print('del 函数测试')
    del a[0]
    print(a)

    print('切片测试')
    b = a[2:5:]
    print(b)

    print('for 语句测试')
    for each in a:
        print(a)
    print()
    for each in a:
        print(each, end='->')
    print()

    print('[]索引赋值测试:')
    a[-1] = 100
    print(a)
排序测试:
16->4->15->1->20->7->5->15->2->3->
1->2->3->4->5->7->15->15->16->20->
20->16->15->15->7->5->4->3->2->1->
del 函数测试
16->15->15->7->5->4->3->2->1->
切片测试
15->7->5->
for 语句测试
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->
16->15->15->7->5->4->3->2->1->

16->15->15->7->5->4->3->2->1->
[]索引赋值测试:
16->15->15->7->5->4->3->2->100->
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值