算法基础之链表理论


1.链表基础定义

之前已经把两大数据结构之一的数组总结了,这次就来总结另一个——链表(Linked List)。首先动态数组、栈和队列的底层都是依托于静态数组的;靠resize来解决固定容量问题,这可能会造成内存空间的大量浪费(比如当数组满了后,会自动加倍容量,但如果没有继续添加元素,其实是有多一倍的容量浪费了);插入和删除时需要移动大量元素。而链表则是真正的动态数据结构
一句话总结:数据存储在‘节点’(Node)中
在这里插入图片描述
如果一个节点的next是空的,则它就是最后一个节点了。因此,链表的优点是实现真正的动态,不需要处理固定容量的问题;而缺点是丧失了随机访问的能力(因为链表节点在计算机底层内存的位置不是连续的)
所以,再跟数组来对比如下:
在这里插入图片描述

2.链表增删改查

2.1基本功能

链表的第一个元素我们定义为head。
在这里插入图片描述

class LinkedList:
    class _Node:
        def __init__(self, e=None):
            self.e = e
            self.next = None

        def __str__(self):
            return str(self.e)

        def __repr__(self):
            return self.__str__()

    def __init__(self):
        self.__head = None
        self._size = 0

    def get_size(self):
        return self._size

    def is_empty(self):
        return self._size == 0

2.2链表添加元素

之前数组我们是在尾部添加元素是方便的(因为数组的size变量是指向数组中最后一个元素的下一个位置,即下一个添加元素的位置),而链表是在头部添加元素更加方便。
比如现在我们想把内容为666的一个节点添加到链表的头部,且不破坏链表原有结构。
在这里插入图片描述
先把666的节点的next指向现在的链表head。
在这里插入图片描述
然后把head指向666的节点。
在这里插入图片描述
头部添加的实现如下(跟栈类似):

def add_first(self, e):
        node = self._Node(e)
        node.next = self.__head
        self.__head = node
        self._size += 1

而尾部添加的实现跟队列比较类似:

def add_last(self, e):
        node = self._Node(e)
        if self.__head is None:
            self.__head = node
            self._size += 1
            return
        cur = self.__head
        pre = None
        while cur:
            pre = cur
            cur = cur.next
            # 当cur 为最后一个节点时带入,pre更新为最后一个节点,cur更新为最后一个节点的下一个节点即为空,
            # 下一次while cur 时会退出循环,此时的pre表示的就是最后一个节点,将node挂到pre的后面即可
        pre.next = node
        self._size += 1
        # 查找链表中有没有item,有返回True,没有则返回False

现在我们想在链表任意位置添加元素,比如在‘索引’(链表其实没有索引这个概念)为2的地方添加元素666,即我们需要在1和2中间插入一个666。
在这里插入图片描述
首先我们需要搜索一下666之前的节点是谁,显然我们插入666后索引是2,则之前的节点就从0开始遍历到索引为1的位置(prev找到1)。
在这里插入图片描述
然后就把666插入(注意顺序!)。
在这里插入图片描述

在这里插入图片描述
所以关键是要找到待插入节点的前一个位置(prev指向的位置)。然而,如果我们如果要插入头部的位置的话,head是没有前面的位置的,这时我们需要做一个特殊的处理。具体实现如下:

def add(self, index, e):
        if index < 0 or index > self._size:
            raise ValueError('Add failed. Illegal index.')
        if index == 0:
            #特殊情况:插到链表头部,
            self.add_first(e)
            return
        prev = self.__head
        for i in range(index-1):
            prev = prev.next
        node = self._Node(e)
        node.next = prev.next
        prev.next = node
        self._size += 1 

然后前面的add_first和add_last都可以调用add了:

def add_first(self, e):
        self.add(0, e)
def add_last(self, e):
        self.add(self._size, e)

另外我们思考插入666的时候能不能把两个步骤的顺序换一下呢?首先,如果先把prev指向666,这时候2是没有指向它了,那自然是找不到它的位置了。
在这里插入图片描述
在这里插入图片描述
然后我们建一个打印链表的函数,方便查看插入的程序对不对。

def __str__(self):
        curr = self.__head
        data = []
        while curr:
            data.append(str(curr.e))
            curr = curr.next
        return '(Head) ' + \
            ' -> '.join(data) + ' (Tail)'

def __repr__(self):
        return self.__str__()

检验一下!

if __name__ == '__main__':
    linkedlist = LinkedList()
    print(linkedlist.get_size())
    linkedlist.add_first(1)
    linkedlist.add_first(2)
    linkedlist.add_first(4)
    linkedlist.add_first(5)
    print(linkedlist)
    linkedlist.add(1,6)
    print(linkedlist)
0
(Head) 5 -> 4 -> 2 -> 1 (Tail)
(Head) 5 -> 6 -> 4 -> 2 -> 1 (Tail)

我们再来深究一下为什么在链表头部添加元素会比较特殊呢?因为head是没有前面的节点的,所以逻辑上会特殊一点。但是我们可以在head前面设立一个虚拟头节点(不存储任何元素),即链表真正的头节点(dummyHead),但这个虚拟头节点是对用户屏蔽的。这时就不需要对头节点进行特殊处理了。
在这里插入图片描述
在这里插入图片描述
有了这个虚拟头节点后,我们可以改写一下之前的功能:

class LinkedList:
    class _Node:
        def __init__(self, e=None):
            self.e = e
            self.next = None

        def __str__(self):
            return str(self.e)

        def __repr__(self):
            return self.__str__()
    '''
    原来的初始化
    def __init__(self):
        self.__head = None
        self._size = 0
    '''
    def __init__(self):
        self._dummy_head = self._Node()#dummyhead的节点没有内容
        self._size = 0

    def get_size(self):
        return self._size

    def is_empty(self):
        return self._size == 0

    def add_first(self, e):
        self.add(0, e)

    def add_last(self, e):
        self.add(self._size, e)

    def add(self, index, e):
        if index < 0 or index > self._size:
            raise ValueError('Add failed. Illegal index.')
        '''
        if index == 0:
            self.add_first(e)
            return
        prev = self.__head
        '''
        prev = self._dummy_head
        for i in range(index-1):
            prev = prev.next
        node = self._Node(e)
        node.next = prev.next
        prev.next = node
        self._size += 1

   
    def __str__(self):
        '''
        curr = self.__head
        '''
        curr = self._dummy_head.next
        data = []
        while curr:
            data.append(str(curr.e))
            curr = curr.next
        return '<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) ' + \
            ' -> '.join(data) + ' (Tail)'

    def __repr__(self):
        return self.__str__()

2.3链表遍历、查询、更新

def get(self, index):
    if index < 0 or index >= self._size:
        raise ValueError('Get failed. Illegal index.')
    curr = self._dummy_head.next
    for i in range(index):
        curr = curr.next
    return curr.e
  

def get_first(self):
    return self.get(0)

def get_last(self):
    return self.get(self._size - 1)

def setter(self, index, e):
    if index < 0 or index >= self._size:
        raise ValueError('Set failed. Illegal index.')
    curr = self._dummy_head.next
    for i in range(index):
        curr = curr.next
    curr.e = e

def contains(self, e):
    curr = self._dummy_head.next
    while curr:
        if curr.e == e:
            return True
        curr = curr.next
    return False

def __str__(self):
    curr = self._dummy_head.next
    data = []
    while curr:
        data.append(str(curr.e))
        curr = curr.next
    return '<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) ' + \
        ' -> '.join(data) + ' (Tail)'

def __repr__(self):
    return self.__str__()

检验:

if __name__ == '__main__':
    linkedlist = LinkedList()
    print(linkedlist.get_size())
    linkedlist.add_first(1)
    linkedlist.add_first(2)
    linkedlist.add_first(4)
    linkedlist.add_first(5)

    print(linkedlist.get_size())
    print(linkedlist)
    print(linkedlist.get(3))
    print(linkedlist.get_first())
    print(linkedlist.get_last())
    linkedlist.setter(3,6)
    print(linkedlist)
0
4
<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) 5 -> 4 -> 2 -> 1 (Tail)
1
5
1
<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) 5 -> 4 -> 2 -> 6 (Tail

2.4链表删除元素

比如我们要删除索引为2位置的元素(记住链表是没有索引的概念,只是为了方便这里讲解)。
在这里插入图片描述
首先我们要找到2之前的那个节点,即prev的指向的位置。
在这里插入图片描述
在这里插入图片描述
把2跳过,现在的2顺序上是找不到它的位置了。
在这里插入图片描述
另外为了python尽可能回收空间,我们手动让2的节点为空,即delNode.next = null。此时真正意义上把2从链表里删除了。
在这里插入图片描述

def remove(self, index):
    if index < 0 or index >= self._size:
        raise ValueError('Remove failed. Illegal index.')
    prev = self._dummy_head
    for i in range(index):
        prev = prev.next
    ret = prev.next
    prev.next = ret.next
    ret.next = None
    self._size -= 1
    return ret.e

def remove_first(self):
    return self.remove(0)

def remove_last(self):
    return self.remove(self._size - 1)

def __str__(self):
    curr = self._dummy_head.next
    data = []
    while curr:
        data.append(str(curr.e))
        curr = curr.next
    return '<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) ' + \
        ' -> '.join(data) + ' (Tail)'

def __repr__(self):
    return self.__str__()

检验:

if __name__ == '__main__':
    linkedlist = LinkedList()
    print(linkedlist.get_size())
    linkedlist.add_first(1)
    linkedlist.add_first(2)
    linkedlist.add_first(4)
    linkedlist.add_first(5)

    print(linkedlist)
    linkedlist.remove(2)
    linkedlist.remove_first()
    linkedlist.remove_last()
    print(linkedlist)
0
<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) 5 -> 4 -> 2 -> 1 (Tail)
<chapter_04_LinkedList.linkedlist.LinkedList>: (Head) 4 (Tail)

3.静态链表

这个内容是把一个数据结构转化成另一个数据结构,但难度较大,在面试中也不常见,属于拓展思路的内容。
链表及下面涉及的新链表形式都是依赖于指针实现的,但早期的编程语言没有指针,有人想出用数组来代替指针从而表示单链表。
首先我们让数组的元素都由两个数据域来组成(val表示数据内容和cur相当于链表中next指针)。另外,我们对数组第一个和最后一个元素都做了特殊处理,不存数据(都是有意去浪费这两个空间)。
在这里插入图片描述
来看一个例子,现在我们已经把一组数据(甲乙丙…庚)存放到静态链表里,能看到甲存有下一个元素乙的游标值(即2),以此类推,直到庚是最后一个有值的元素,我们就把庚的cur设置为0。最后一个元素存的是第一个有值元素的下标(即1),第一个元素存的是备用列表的第一个位置下标(即7).
在这里插入图片描述
现在我们打算把丙插入乙和丁之间,第一步我们把丙扔到空闲空间第一位(即7),第二步告诉乙把它的cur改成7,第三步把丙的cur改成3,搞定!其实跟单链表插入的原理差不多。
在这里插入图片描述

#静态链表
class Node:
    def __init__(self, cur, val=None):
       # 值
       self.val = val
       # 游标。最后一个元素的游标必须是0
       self.cur = cur
    
class linkList:
    
    # 分配线性表长度、定义线性表
    def __init__(self):
        self.MAX_SIZE = 7 #一般会设为1000这样大的空间,防止插入后溢出,这里是为了方便之后打印检查
        self.node = list()
        for i in range(self.MAX_SIZE):
            if i == self.MAX_SIZE-1:
                self.node.append(Node(0))
            else:
                self.node.append(Node(i+1))
    
    # 指定位置插入元素
    def add(self, i, e):
        
        k = self.MAX_SIZE-1
        if i < 1 or i > self.ListLength()+1:
            return 0
        j = self.findEmpty()
        if (j):
            self.node[j].val = e
            for l in range(1,i):
                k = self.node[k].cur
            self.node[j].cur = self.node[k].cur
            self.node[k].cur = j
            return 1
        return 0
    
       # 查找空位置
    def findEmpty(self):
        i = self.node[0].cur
        if (self.node[0].cur):
            self.node[0].cur = self.node[i].cur   
        return i  
    
    def ListLength(self):
        j = 0
        i = self.node[self.MAX_SIZE-1].cur
        
        while(i):
            i = self.node[i].cur
            j = j+1
        return j      
    
    # 删除线性表指定位置的元素
    def remove(self, i):
        if i < 1 or i > self.ListLength():
            return 0
        k = self.MAX_SIZE-1
        for j in range(1,i):
            k = self.node[k].cur 
        j = self.node[k].cur
        self.node[k].cur = self.node[j].cur
        self.delempty(j)
    
    def delempty(self, k):
        self.node[k].cur = self.node[0].cur
        self.node[0].cur = k

    # 按照索引遍历
    def travel(self):
        for i in range(0, self.MAX_SIZE):
            print("i==", i, "; val==", self.node[i].val, "; cur==", self.node[i].cur)
ll = linkList()
ll.travel()
print("start")
ll.add(1, 'B')
ll.travel()
print("start")
ll.add(2, 'Bc')
ll.travel()
print("start")
ll.add(3, 'Bcd')
ll.travel()
print("del")
ll.remove(1)
ll.travel()
i== 0 ; val== None ; cur== 1
i== 1 ; val== None ; cur== 2
i== 2 ; val== None ; cur== 3
i== 3 ; val== None ; cur== 4
i== 4 ; val== None ; cur== 5
i== 5 ; val== None ; cur== 6
i== 6 ; val== None ; cur== 0
start
i== 0 ; val== None ; cur== 2
i== 1 ; val== B ; cur== 0
i== 2 ; val== None ; cur== 3
i== 3 ; val== None ; cur== 4
i== 4 ; val== None ; cur== 5
i== 5 ; val== None ; cur== 6
i== 6 ; val== None ; cur== 1
start
i== 0 ; val== None ; cur== 3
i== 1 ; val== B ; cur== 2
i== 2 ; val== Bc ; cur== 0
i== 3 ; val== None ; cur== 4
i== 4 ; val== None ; cur== 5
i== 5 ; val== None ; cur== 6
i== 6 ; val== None ; cur== 1
start
i== 0 ; val== None ; cur== 4
i== 1 ; val== B ; cur== 2
i== 2 ; val== Bc ; cur== 3
i== 3 ; val== Bcd ; cur== 0
i== 4 ; val== None ; cur== 5
i== 5 ; val== None ; cur== 6
i== 6 ; val== None ; cur== 1
del
i== 0 ; val== None ; cur== 1
i== 1 ; val== B ; cur== 4
i== 2 ; val== Bc ; cur== 3
i== 3 ; val== Bcd ; cur== 0
i== 4 ; val== None ; cur== 5
i== 5 ; val== None ; cur== 6
i== 6 ; val== None ; cur== 2

总的来说,静态链表的优点是插入和删除元素时,我们只需要更改游标,而不需要直接移动元素;缺点是它依然是一个静态结构,而且失去顺序存储结构能随机存储的一个特性(现在的index和cur不是一一对应的)。本质上,静态链表只是为了那些没有指针的高级语言所设计的方法。

4.双向链表

引例:
当一辆高铁起点站是上海,终点站是北京,现在我们想从北京去上海,but链表不能反向遍历。
在这里插入图片描述
所以我们在一个节点里面加了个指向前端节点的prev,这样一个节点既可以指向前方,也可以指向后方,这种能提升链表综合性能的新形式是双向链表。

#双向链表
class Node(object):
    def __init__(self, elem):
        """双链表结点"""
        self.elem = elem
        self.pre = None
        self.next = None


class DoubleLinkedList(object):
    def __init__(self, node=None):
        self.__head = node

    def is_empty(self):
        """判断链表是否为空"""
        return self.__head is None

    def length(self):
        """获取链表长度"""
        cur = self.__head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历链表"""
        cur = self.__head
        while cur is not None:
            print(cur.elem, end=' ')
            cur = cur.next
        print()

    def addFirst(self, elem):
        """向双链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():  # 链表为空
            self.__head = node
        else:
            node.next = self.__head
            node.next.pre = node
            self.__head = node

    def addLast(self, elem):
        """向链表尾部添加结点"""
        node = Node(elem)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next is not None:
                cur = cur.next
            cur.next = node
            node.pre = cur

    def add(self, pos, elem):
        """向链表位置pos处插入元素elem"""
        if pos == 0:
            self.addFirst(elem)
        elif pos > self.length() or pos < 0:
            raise ValueError('Add failed. Illegal index.')
        else:
            node = Node(elem)
            cur = self.__head
            pre = None
            for i in range(pos):
                pre = cur
                cur = cur.next
            pre.next = node
            node.pre = pre
            node.next = cur
            if cur:
                cur.pre = node

    def remove(self, elem):
        """删除链表中第一个值为elem的结点"""
        if self.is_empty():
            return
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                if cur == self.__head:  # 若是头结点
                    self.__head = cur.next  # 链表中只有一个结点
                    if cur.next:
                        cur.next.pre = None
                else:
                    cur.pre.next = cur.next
                    if cur.next:  # 如果不是尾结点
                        cur.next.pre = cur.pre
                break
            else:
                cur = cur.next

    def search(self, elem):
        """查找链表中是否存在元素elem"""
        cur = self.__head
        while cur is not None:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        return False
if __name__ == '__main__':
    double_linked_list = DoubleLinkedList()
    print(double_linked_list.is_empty())
    print('===================')
    double_linked_list.addLast(1)
    print('===================')
    double_linked_list.addLast(2)
    double_linked_list.addLast(3)

    double_linked_list.addFirst(7)

    double_linked_list.addLast(4)
    double_linked_list.addLast(5)

    double_linked_list.add(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    double_linked_list.travel()

    double_linked_list.add(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    double_linked_list.travel()

    double_linked_list.add(8, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    double_linked_list.travel()

    double_linked_list.remove(13)
    double_linked_list.travel()  # 7 99 1 2 3 4 5 22

    double_linked_list.remove(22)
    double_linked_list.travel()  # 7 99 1 2 3 4 5

    double_linked_list.remove(3)
    double_linked_list.travel()  # 7 99 1 2 4 5

    print(double_linked_list.search(100))  # False
    print(double_linked_list.search(7))  # True
    print(double_linked_list.search(2))  # True
    print(double_linked_list.search(5))  # True
True
===================
===================
13 7 1 2 3 4 5 
13 7 99 1 2 3 4 5 
13 7 99 1 2 3 4 5 22 
7 99 1 2 3 4 5 22 
7 99 1 2 3 4 5 
7 99 1 2 4 5 
False
True
True
True

5.单向循环链表

引例:
当一辆高铁起点站是上海,终点站是北京,现在我们想从南京直接去北京,but链表要求我们必须从头开始遍历,实在不方便。
在这里插入图片描述

单链表终端的节点的next一般指向null,现在把它指向头节点,使得整个链表成为一个环,这种头尾相连的链表就称为单向循环链表。
在这里插入图片描述
这种新链表形式解决了一个问题:我们可以从当中的一个节点出发,然后可以访问链表全部节点。

#单向循环链表
class Node(object):
    def __init__(self, elem):
        """单循环链表结点"""
        self.elem = elem
        self.next = None


class SinglyLinkedCircularList(object):
    """单向循环链表"""
    def __init__(self, node=None):
        self.__head = node

    def is_empty(self):
        """判断链表是否为空"""
        return self.__head is None

    def length(self):
        """求链表长度"""
        if self.is_empty():
            return 0
        cur = self.__head
        count = 1  # 下方循环退出时,链表至少有一个结点
        while cur.next != self.__head:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历链表"""
        if self.is_empty():
            return
        cur = self.__head
        while cur.next != self.__head:
            print(cur.elem, end=' ')
            cur = cur.next
        # 退出循环时,cur指向最后一个结点
        print(cur.elem)

    def addFirst(self, elem):
        """向链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():
            node.next = node
            self.__head = node
        else:
            node.next = self.__head
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            cur.next = node
            self.__head = node
           

    def addLast(self, elem):
        """向链表尾部添加元素"""
        node = Node(elem)
        if self.is_empty():
            node.next = node
            self.__head = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            node.next = self.__head
            cur.next = node

    def add(self, pos, elem):
        """向链表位置pos处插入元素

        Args:
            pos: 插入的位置,从0开始计数
            elem: 插入的元素
        """
        if pos <= 0:
            self.addFirst(elem)
        elif pos > (self.length() - 1):
            self.addLast(elem)
        else:
            pre = self.__head
            count = 0
            while count < (pos - 1):
                count += 1
                pre = pre.next
            # 退出循环,pre指向插入位置的前一个结点
            node = Node(elem)
            node.next = pre.next
            pre.next = node

    def remove(self, elem):
        """删除链表中第一个为elem的元素"""
        if self.is_empty():
            return
        cur = self.__head
        pre = None
        if cur.elem == elem:
            if cur.next != self.__head:
                while cur.next != self.__head:
                    cur = cur.next
                cur.next = self.__head.next
                self.__head = self.__head.next
            else:
                self.__head = None
        else:
            pre = self.__head
            while cur.next != self.__head:
                if cur.elem == elem:
                    pre.next = cur.next
                    return
                else:
                    pre = cur
                    cur = cur.next
            if cur.elem == elem:
                pre.next = cur.next
        

    def search(self, elem):
        """查找链表中是否存在元素elem"""
        if self.is_empty():
            return False
        cur = self.__head
        while cur.next != self.__head:
            if cur.elem == elem:
                return True
            else:
                cur = cur.next
        # 退出循环,cur指向尾结点
        if cur.elem == elem:
            return True
        return False
if __name__ == '__main__':
    singly_linked_circular_list = SinglyLinkedCircularList()
    print(singly_linked_circular_list.is_empty())
    print(singly_linked_circular_list.length())
    print('===================')

    singly_linked_circular_list.addLast(1) #1
    print(singly_linked_circular_list.is_empty())
    print(singly_linked_circular_list.length())
    print('===================')

    singly_linked_circular_list.addLast(2)#1,2
    singly_linked_circular_list.addLast(3)#1,2,3

    singly_linked_circular_list.addFirst(7)

    singly_linked_circular_list.addLast(4)
    singly_linked_circular_list.addLast(5) # 7, 1, 2, 3, 4, 5

    singly_linked_circular_list.add(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    singly_linked_circular_list.travel()

    singly_linked_circular_list.add(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    singly_linked_circular_list.travel()

    singly_linked_circular_list.add(11, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    singly_linked_circular_list.travel()

    singly_linked_circular_list.remove(13)
    singly_linked_circular_list.travel()  # 7 99 1 2 3 4 5 22

    singly_linked_circular_list.remove(22)
    singly_linked_circular_list.travel()  # 7 99 1 2 3 4 5

    singly_linked_circular_list.remove(3)
    singly_linked_circular_list.travel()  # 7 99 1 2 4 5

    print(singly_linked_circular_list.search(666))  # False
    print(singly_linked_circular_list.search(7))  # True
    print(singly_linked_circular_list.search(5))  # True
    print(singly_linked_circular_list.search(1))  # True
True
0
===================
False
1
===================
13 7 1 2 3 4 5
13 7 99 1 2 3 4 5
13 7 99 1 2 3 4 5 22
7 99 1 2 3 4 5 22
7 99 1 2 3 4 5
7 99 1 2 4 5
False
True
True
True

6.双向循环链表

#双向循环链表
class Node(object):
    def __init__(self, elem):
        """双链表结点"""
        self.elem = elem  # 该节点值
        self.next = None   # 连接一下一个节点
        self.prev = None  # 上一个节点值


class DoubleCircleLinkedList(object):
    def __init__(self, node=None):
        self._head = node

    def is_empty(self):
        """判断链表是否为空"""
        return self._head is None

    def length(self):
        """获取链表长度"""
        if self.is_empty():
            return 0
        else:
            cur = self._head.next
            n = 1
            while cur != self._head:
                cur = cur.next
                n += 1
            return n

    def travel(self):
        """遍历链表"""
        cur = self._head
        while cur.next != self._head:
            print(cur.elem, end=' ')
            cur = cur.next
        print(cur.elem)
        
    def addFirst(self, elem):
        """向双链表头部添加元素"""
        node = Node(elem)
        if self.is_empty():  # 链表为空
            node.next = node
            node.prev = node
            self._head = node
        else:
            node.next = self._head
            node.prev = self._head.prev
            self._head.prev.next = node
            self._head.prev = node
            self._head = node

    def addLast(self, elem):
        """向链表尾部添加结点"""
        if self.is_empty():
            self.addFirst(elem)
        else:
            node = Node(elem)
            cur = self._head.next
            while cur.next != self._head:
                cur = cur.next
            cur.next = node
            node.prev = cur
            node.next = self._head
            self._head.prev = node

    def add(self, pos, elem):
        """向链表位置pos处插入元素elem"""
        if pos <= 0:
            self.addFirst(elem)
        elif pos >= self.length():
            self.addLast(elem)
        else:
            cur = self._head.next
            n = 1
            while cur.next != self._head:
                if n == pos:
                    break
                cur = cur.next
                n += 1
            node = Node(elem)
            node.prev = cur.prev
            cur.prev.next = node
            node.next = cur
            cur.prev = node

    def remove(self, elem):
        """删除链表中第一个值为elem的结点"""
        if self.is_empty():
            return
        else:
            if self._head.elem == elem:
                if self.length == 1:
                    self._head = Node
                else:
                    self._head.prev.next = self._head.next
                    self._head.next.prev = self._head.prev
                    self._head = self._head.next
            cur = self._head.next
            while cur != self._head:
                if cur.elem == elem:
                    cur.prev.next = cur.next
                    cur.next.prev = cur.prev
                cur = cur.next

    def search(self, elem):
        """查找链表中是否存在元素elem"""
        if self.is_empty():
            return False
        else:
            cur = self._head.next
            if self._head.elem == elem:
                return True
            else:
                while cur != self._head:
                    if cur.elem == elem:
                        return True
                    else:
                        cur = cur.next
                return False
if __name__ == '__main__':
    double_linked_list = DoubleCircleLinkedList()
    double_linked_list.addLast(1)
    double_linked_list.addLast(2)
    double_linked_list.addLast(3)
    double_linked_list.addFirst(7)
    double_linked_list.addLast(4)
    double_linked_list.addLast(5)

    double_linked_list.add(0, 13)  # 13, 7, 1, 2, 3, 4, 5
    double_linked_list.travel()

    double_linked_list.add(2, 99)  # 13, 7, 99, 1, 2, 3, 4, 5
    double_linked_list.travel()

    double_linked_list.add(11, 22)  # 13, 7, 99, 1, 2, 3, 4, 5, 22
    double_linked_list.travel()

    double_linked_list.remove(13)
    double_linked_list.travel()  # 7 99 1 2 3 4 5 22

    double_linked_list.remove(22)
    double_linked_list.travel()  # 7 99 1 2 3 4 5

    double_linked_list.remove(3)
    double_linked_list.travel()  # 7 99 1 2 4 5

    print(double_linked_list.search(100))  # False
    print(double_linked_list.search(7))  # True
    print(double_linked_list.search(2))  # True
    print(double_linked_list.search(5))  # True
13 7 1 2 3 4 5
13 7 99 1 2 3 4 5
13 7 99 1 2 3 4 5 22
7 99 1 2 3 4 5 22
7 99 1 2 3 4 5
7 99 1 2 4 5
False
True
True
True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值