zoukankan      html  css  js  c++  java
  • 链表

    一: 链表的引入

    1 链表的功能

    1 顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。
    2 链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。

    2 链表的概念

    1 链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
    2 链表是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个结点(数据存储单元)里存放下一个结点的位置信息(即地址)。

    二:单向链表

    1 单向链表的概念

    1 单向链表也叫单链表,是链表中最简单的一种形式。
    2 它的每个结点包含两个域,一个信息域(元素域)和一个链接域。
    3 这个链接指向链表中的下一个结点,而最后一个结点的链接域则指向一个空值。

    2 单向链表的操作

    1 is_empty() 链表是否为空
    2 length() 链表长度
    3 travel() 遍历整个链表
    4 append(item) 链表尾部添加元素
    5 add(item) 链表头部添加元素
    6 insert(pos, item) 指定位置添加元素
    7 search(item) 查找结点是否存在
    8 remove(item) 删除结点

    3 单个节点的实现

    # 定义链表的单个结点
    class Node():
        # 构造方法初始化结点
        def __init__(self, elem):
            # 初始化数据区
            self.elem = elem
            # 初始化链接区
            self.next = None

    4 单链表的实现

     初始化

    # 定义单链表
    class single_linked_list():
        # 构造链表,若结点没值指向None
        def __init__(self,node=None):
            # __head代表头结点
            self.__head = node

     判断非空

    # 判断链表是否为空
    def is_empty(self):
        # head指向None则为空
        return self.__head is None

     cur游标代表当前结点

     

    # 查长度
    def length(self):
        # 判断空
        if self.is_empty():
            return 0
        else:
            # 定义游标
            cur = self.__head
            # 计数
            count = 0
            # 循环
            while cur != None:
                # 让游标移动
                cur = cur.next
                count += 1
            return count

    l 遍历,注意进循环后先打印,再移动游标

    def travel(self):
        if self.is_empty():
            return
        else:
            # 游标
            cur = self.__head
            while cur != None:
                # 先打印
                print(cur.elem,end= ' ')
                cur = cur.next
            print('')

    尾插法

    def append(self,item):
        # 定义新结点
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            # cur到最后一个结点停下
            while cur.next != None:
                # cur移动
                cur = cur.next
            # 此时,cur到达了最后一个结点
            cur.next = node

    头插法

    def add(self,item):
        # 新结点
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            # 这里顺序不能变
            node.next = self.__head
            self.__head = node

    在指定位置添加

    # pos从0开始
    def insert(self,pos,item):
        # 特殊判断,友好一点
        if pos < 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            # 新结点
            node = Node(item)
            pre = self.__head
            count = 0
            while count < (pos -1):
                # 移动游标
                pre = pre.next
                count += 1
            # 此时,pre游标指向插入位置的前一个结点
            # 下面操作顺序不能变
            node.next = pre.next
            pre.next = node

    l 查找元素,循环遍历比对每一个元素

    def search(self,item):
        if self.is_empty():
            return False
        else:
            # 定义游标
            cur = self.__head
            while cur != None:
                # 判断cur的数据是否为查找的数据item
                if cur.elem == item:
                    return True
                else:
                    # 游标移动
                    cur = cur.next
            # 遍历完成,cur指向None
            return False

    删除元素,需要两个游标

    def remove(self,item):
        if self.is_empty():
            return
        else:
            # 定义cur游标
            cur = self.__head
            # 定义pre游标
            pre = None
            # 查找所有的位置有没有要删除的,若有则删
            while cur != None:
                # 判断cur指向的数据,是否为要删的数据
                if cur.elem == item:
                    # 考虑特殊情况,恰好要删的是第一个元素
                    if cur == self.__head:
                        # 头结点指向后一个结点
                        self.__head = cur.next
                    else:
                        # 删除
                        pre.next = cur.next
                    return
                else:
                    # 移动游标,先移动pre,再移动cur
                    pre = cur
                    cur = cur.next

    测试

    if __name__ == '__main__':
        sll = single_linked_list()
        print(sll.is_empty())
        print(sll.length())
        print('--------------------------')
        sll.travel()
        print('--------------------------')
        sll.append(2)
        sll.add(3)
        sll.append(5)
        sll.travel()
        print('--------------------------')
        print(sll.is_empty())
        print(sll.length())
        print('--------------------------')
        sll.insert(1,'abc')
        sll.travel()
        print(sll.search(5))
        print('--------------------------')
        sll.remove('abc')
        sll.travel()

    5 链表与顺序表的对比

    1 链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。
    2 请填写链表与顺序表各种操作的时间复杂度:

    操作

    链表

    顺序表

    访问元素

    O(n)

    O(1)

    在头部插入/删除

    O(1)

    O(n)

    在尾部插入/删除

    O(n)

    O(1)

    在中间插入/删除

    O(n)

    O(n)

     三  双向链表

     1 双向链表的概念

    1 一种更复杂的链表是“双向链表”或“双面链表”。
    2 每个结点有两个链接:一个指向前一个结点,当此结点为第一个结点时,指向空值。
    3 而另一个指向下一个结点,当此结点为最后一个结点时,指向空值。
    4 前一个结点称为前趋结点,后一个结点称为后继结点

    2 双向链表的操作

    is_empty() 链表是否为空
    length() 链表长度
    travel() 遍历整个链表
    append(item) 链表尾部添加元素
    add(item) 链表头部添加元素
    insert(pos, item) 指定位置添加元素
    search(item) 查找结点是否存在
    remove(item) 删除结点

    3 单个节点的实现

    # 定义双向链表的结点
    class Node:
        def __init__(self,elem):
            # 初始化数据区
            self.elem = elem
            self.next = None
            self.prev = None

    4 双向链表的实现

    # 实现双链表
    class double_linked_list:
        # 构造链表,若结点没值指向None
        def __init__(self,node=None):
            # __head代表头结点
            self.__head = node
        # 判断链表是否为空
        def is_empty(self):
            # head指向None则为空
            return self.__head is None
        # 查长度
        def length(self):
            # 判断空
            if self.is_empty():
                return 0
            else:
                # 定义游标
                cur = self.__head
                # 计数
                count = 0
                # 循环
                while cur != None:
                    # 让游标移动
                    cur = cur.next
                    count += 1
                return count
        def travel(self):
            if self.is_empty():
                return
            else:
                # 游标
                cur = self.__head
                while cur != None:
                    # 先打印
                    print(cur.elem,end= ' ')
                    cur = cur.next
                print('')

    尾插要处理前驱

    def append(self,item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            # 移动游标
            cur = self.__head
            while cur.next != None:
                cur = cur.next
            # 此时,cur指向最后一个结点
            cur.next = node
            # 处理前驱结点
            node.prev = cur

    头插

    def add(self,item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            # 新结点指向原第一个结点
            node.next = self.__head
            self.__head = node
            # 处理原第一个结点的前驱
            node.next.prev = node

    指定位置插入

    def insert(self,pos,item):
        if pos < 0:
            self.add(item)
        elif pos > (self.length() -1):
            self.append(item)
        else:
            # 创建结点
            node = Node(item)
            # 游标
            cur = self.__head
            count = 0
            # 因为cur停在后一个位置,所以看图吧
            while count < pos:
                cur = cur.next
                count += 1
            # 此时,cur停在后一个结点
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node

    删除元素

    def remove(self,item):
        if self.is_empty():
            return
        else:
            cur = self.__head
            while cur != None:
                # 对比是否为要删的元素
                if cur.elem == item:
                    # 考虑特殊情况,若找到的结点,恰好为第一个结点
                    if cur == self.__head:
                        # 头直接指向后一个结点
                        self.__head = cur.next
                        # 考虑链表只有一个结点的情况下,None.prev会出问题
                        if cur.next:
                            cur.next.prev = None
                    else:
                        # 当前结点的前一个指向后一个
                        cur.prev.next = cur.next
                        # 考虑后面没有结点的情况
                        if cur.next:
                            cur.next.prev = cur.prev
                    return
                else:
                    cur = cur.next

    l 测试用前面的代码

    if __name__ == '__main__':
        sll = single_linked_list()
        print(sll.is_empty())
        print(sll.length())
        print('--------------------------')
        sll.travel()
        print('--------------------------')
        sll.append(2)
        sll.add(3)
        sll.append(5)
        sll.travel()
        print('--------------------------')
        print(sll.is_empty())
        print(sll.length())
        print('--------------------------')
        sll.insert(1,'abc')
        sll.travel()
        print(sll.search(5))
        print('--------------------------')
        sll.remove('abc')
        sll.travel()

    四 单向循环链表

    1单向循环链表的概念

    1 单链表的一个变形是单向循环链表。
    2 链表中最后一个结点的next域不再为None,而是指向链表的头结点。

    2 单向循环链表的操作

    is_empty() 链表是否为空
    length() 链表长度
    travel() 遍历整个链表
    append(item) 链表尾部添加元素
    add(item) 链表头部添加元素
    insert(pos, item) 指定位置添加元素
    search(item) 查找结点是否存在
    remove(item) 删除结点

    3单个节点的实现(与单向链表一样)

    4 单向循环链表的实现

    定义单向循环链表

    # 定义单向循环链表
    class single_loop_list:
        def __init__(self,node=None):
            self.__head = node
            # 特殊处理回环
            if node:
                node.next = node

    求长度

    def length(self):
        if self.is_empty():
            return 0
        else:
            cur = self.__head
            # count从1开始
            count = 1
            while cur.next != self.__head:
                # 移动
                cur = cur.next
                count += 1
            return count

    遍历,注意不要把最后一个漏掉了

    def travel(self):
        if self.is_empty():
            return
        else:
            cur = self.__head
            while cur.next != self.__head:
                # 先打印再移动游标
                print(cur.elem,end=' ')
                cur = cur.next
            # 退出循环,cur指向了尾结点
            print(cur.elem,end=' ')
            print('')

    尾插法,处理回环

    def append(self,item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
            # 处理回环
            node.next = node
        else:
            # 游标走到最后
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            # cur此时在最后一个位置
            # 新结点指向头
            node.next = self.__head
            # 原最后结点,指向新结点
            cur.next = node

    头插,要处理回环

    def add(self,item):
        # 结点
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = node
        else:
            cur =self.__head
            # 移动游标
            while cur.next != self.__head:
                cur = cur.next
            # cur停留在最后的位置
            node.next = self.__head
            self.__head = node
            # 形成回环
            cur.next = node

     指定位置插入,与单向链表一样

    查找元素,注意别丢下最后一个

    def search(self,item):
        if self.is_empty():
            return False
        else:
            # 定义游标
            cur = self.__head
            while cur.next != self.__head:
                # 判断cur的数据是否为查找的数据item
                if cur.elem == item:
                    return True
                else:
                    # 游标移动
                    cur = cur.next
            # 处理最后一个结点
            if cur.elem == item:
                return True
            # 遍历完成,cur指向None
            return False

    删除元素

    def remove(self, item):
        if self.is_empty():
            return
        else:
            cur = self.__head
            pre = None
            # 循环条件
            while cur.next != self.__head:
                # 判断cur的数据是否为要删的数据
                if cur.elem == item:
                    if cur == self.__head:
                        # 考虑删的恰好是第一个结点
                        # 考虑回环,还需要一个游标拿到尾结点位置
                        # 这里直接将rear移动到最后即可
                        rear = self.__head
                        while rear.next != self.__head:
                            rear = rear.next
                        # 此时rear指向最后一个结点
                        self.__head = cur.next
                        # 回环
                        rear.next = self.__head
                    else:
                        # 其他结点
                        pre.next = cur.next
                    return
                else:
                    # 移动游标
                    pre = cur
                    cur = cur.next
            # 退出循环时,cur指向最后一个结点
            if cur.elem == item:
                # 考虑只有一个结点
                if cur == self.__head:
                    self.__head = None
                else:
                    pre.next = cur.next
  • 相关阅读:
    基础表达式和运算符
    原型链(_proto_) 与原型(prototype) 有啥关系?
    插件模板
    加减plugin
    原生选项卡、手风琴
    前端基础问题(有答案)
    结构图
    Java环境配置小记
    函数
    砝码称重
  • 原文地址:https://www.cnblogs.com/liucsxiaoxiaobai/p/10792191.html
Copyright © 2011-2022 走看看