数据结构与算法-链表

数据结构与算法-链表

01

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的;

02

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成;

03

每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相比于线性表顺序结构,操作复杂;

04

由于不必须按顺序存储,链表在插入的时候以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1);

05

使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大;

06

链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换;

07

链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表、双向链表以及循环链表。

(1)单向链表:单链表是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。

(2)双向链表:双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

(3)循环链表:循环链表是与单链表一样,是一种链式的存储结构,所不同的是,循环链表的最后一个结点的指针是指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。

链表的特点

01

链表是一种非线性、非顺序的物理结构,是由若干个节点组成;

02

链表采用的是“见缝插针”的存储方法,不要求内存连续,靠next指针关联起来;

03

链表的物理存储方式为随机存储,访问方式为顺序访问;

04

查找节点的时间复杂度为O(n),插入、删除节点的时间复杂度为O(1);

05

链表适用于写操作多,读操作少的场景。

Python实现单链表

01

单链表是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。

单链表节点的链接方向是单向的;相对于数组来说,单链表的的随机访问速度较慢,但是单链表删除/添加数据的效率很高。

# 链式 内存不连续,无法通过下标直接进行访问,追加元素比较方便,find比较麻烦,需要重头到尾进行遍历
# 单链 root节点,head节点,tail节点,每一个节点就是一个Node(value,next)
class Node(object):
    def __init__(self, value=None, next=None):
        self.value, self.next = value, next

class LinkedList(object):
    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        self.root = Node()
        self.length = 0
        self.tail_node = None

    def __len__(self):
        return self.length

    def append(self, value):
        if self.maxsize is not None and len(self) > self.maxsize:
            raise Exception('The list is full')
        node = Node(value)
        tail_node = self.tail_node
        if tail_node is None:
            self.root.next = node
        else:
            tail_node.next = node
        self.tail_node = node
        self.length += 1

    def append_left(self, value):
        headnode = self.root.next
        node = Node(value)
        self.root.next = node
        node.next = headnode
        self.length += 1

    def iter_node(self):
        current_node = self.root.next
        while current_node is not self.tail_node:
            yield current_node
            current_node = current_node.next
        yield current_node

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    def remove(self, value):
        previous_node = self.root
        current_node = self.root.next
        for current_node.value in self.iter_node():
            if current_node.value == value:
                previous_node.next = current_node.next
                if current_node is self.tail_node:
                    self.tail_node = previous_node
                del current_node
                self.length -= 1
                return 1
            else:
                previous_node = current_node
        return -1

    def find(self, value):
        index = 0
        for node in self.iter_node():
            if node.value == value:
                return index
            index += 1
        return -1

    def pop_left(self):
        if self.root.next is None:
            raise Exception('pop from empty linked list')
        head_node = self.root.next
        self.root.next = head_node.next
        self.length -= 1
        value = head_node.value
        del head_node
        return value

    def clear(self):
        for node in self.iter_node():
            del node
        self.root.next = None
        self.length = 0
Python实现双向链表

02

双向链表(双链表)是链表的一种,和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

class Node(object):
    __slots__ = ('value', 'prev', 'next')  # save memory

    def __init__(self, value=None, prev=None, next=None):
        self.value, self.prev, self.next = value, prev, next

class CircularDoubleLinkedList(object):
    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        node = Node()
        node.next, node.prev = node, node
        self.root = node
        self.length = 0

    def __len__(self):
        return self.length

    def headnode(self):
        return self.root.next

    def tail_node(self):
        return self.root.prev

    def append(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception('LinkedList is Full')
        node = Node(value=value)
        tail_node = self.tail_node() or self.root
        tail_node.next = node
        node.prev = tail_node
        node.next = self.root
        self.root.prev = node
        self.length += 1

    def append_left(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception('LinkedList is Full')
        node = Node(value=value)
        if self.root.next is self.root:  # empty
            node.next = self.root
            node.prev = self.root
            self.root.next = node
            self.root.prev = node
        else:
            node.prev = self.root
            headnode = self.root.next
            node.next = headnode
            headnode.prev = node
            self.root.next = node
        self.length += 1

    def remove(self, node):
        if node is self.root:
            return
        else:
            node.prev.next = node.next
            node.next.prev = node.prev
        self.length -= 1
        return node

    def iter_node(self):
        if self.root.next is self.root:
            return
        current_node = self.root.next
        while current_node.next is not self.root:
            yield current_node
            current_node = current_node.next
        yield current_node

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    def iter_node_reverse(self):
        """相比单链表独有的反序遍历"""
        if self.root.prev is self.root:
            return
        current_node = self.root.prev
        while current_node.prev is not self.root:
            yield current_node
            current_node = current_node.prev
        yield current_node


作者:David


欢迎关注微信公众号 :测开笔记