数据结构与算法(三)链表

一.链表

1.什么是链表?

链表(Linked List):是一种常见的基础数据结构,是一只种类线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。
顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行空充时又需要进行数据的搬迁,所以使用起来并不是很灵活。链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
在这里插入图片描述

2.顺序表与链表

在这里插入图片描述

二.单链表

1.单链表

单向链表也叫单链表,每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
在这里插入图片描述

  • 表元素域elem用来存放具体的数据。
  • 链接域next用来存放下一个节点的位置(python中的标识)
  • 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

2.单链表的操作

在这里插入图片描述

class Node(object):
    """单链表的节点封装"""
    def __init__(self, element):
        """element存放数据元素"""
        self.element = element
        self.next = None

    def __str__(self):
        return self.element

class SingleLink(object):
    def __init__(self):
        #初始化,链表为空
        self.head = None
    def is_empty(self):
        #判断链表是否为空
        return self.head == None
    def __len__(self):
        """
        链表长度:
        1.如果当前链表为空, 直接返回0;
        2.如果当前链表不为空, 依次遍历链表的每一个元素,计算长度
        :return:
        """
        if self.is_empty():
            return 0
        else:
            cur = self.head
            lenLink = 0
            while cur != None:
                lenLink += 1
                cur = cur.next
            return lenLink
    def travel(self):
        """遍历链表"""
        if not self.is_empty():
            cur = self.head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)
        else:
            print('空链表')

    def add(self, item):
        """
        头部添加元素
            1. 先创建一个保存item值的节点
            2. 将新节点的链接域next指向头节点,即head指向的位置
            3. 将链表的头head指向新节点
        """
        node = Node(item)
        node.next = self.head
        self.head = node
    def append(self, item):
        """
       尾部添加元素
           1. 先判断链表是否为空,若是空链表,则将head指向新节点
           2. 若不为空,则找到尾部,将尾节点的next指向新节点
       """
        node = Node(item)
        if self.is_empty():
            self.head = node
        else:
            cur = self.head
            while cur.next != None:
                cur = cur.next
            cur.next = node
    def insert(self, index, item):
        """
    指定位置添加元素
        1. 若指定位置index为第一个元素之前,则执行头部插入
        2. 若指定位置超过链表尾部,则执行尾部插入
        3. 否则, 找到指定位置
        """
        if index <= 0:
           self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 当前位置
            cur = self.head
            while count < index - 1:
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node
    def remove(self, item):
        """
            删除指定元素的节点:
             1 2 3 4 5
             1. 如果删除的是头结点, 指针直接指向头结点的下一个节点;
             2. 如果删除的不是头结点, 一直循环, 知道找到要删除的节点元素;
            """
        pre = None
        cur = self.head
        if cur.element == item:
            self.head = self.head.next
        else:
            while cur:
                if cur.element != item:
                    pre = cur
                    cur = cur.next
                else:
                    pre.next = pre.next.next
                    break
    def search(self, item):
        cur = self.head
        while cur:
            if cur.element == item:
                return True
            cur = cur.next
        else:
            return False

if __name__ == '__main__':
    # 实例化单链表对象
    link = SingleLink()
    # 长度获取
    print("链表长度: ", len(link))
    # 遍历链表
    link.travel()
    print("链表是否为空? ", link.is_empty())

    print("添加元素:")
    link.append(1)
    link.append(2)
    link.add(3)
    link.insert(1,'hello')
    # 3 'hello' 1 2

    # 长度获取
    print("链表长度: ", len(link))
    # 遍历链表
    link.travel()
    print("链表是否为空? ", link.is_empty())

    print("删除元素")
    link.remove(1)
    link.travel()
    link.search(2)
    link.travel()```

三.单向循环链表

1.单向循环链表

单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。
在这里插入图片描述

2.单向循环链表的操作

在这里插入图片描述

class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None


class SingleCycLink(object):
    def __init__(self):
        self.head = None

    def is_empty(self):
        return self.head == None

    def __len__(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 trvel(self):
        if not self.is_empty():
            cur = self.head
            while cur.next != self.head:
                print(cur.item, end=',')
                cur = cur.next
            print(cur.item)
        else:
            print('链表为空')

    def add(self, item):
        # 在头部添加
        node = Node(item)
        if self.is_empty():
            self.head = node
            node.next = self.head
        else:
            cur = self.head
            while cur.next != self.head:
                cur = cur.next
            cur.next = node
            node.next = self.head
            self.head = node

    def append(self, item):
        # 在尾部添加
        node = Node(item)
        if self.is_empty():
            self.head = node
            node.next = self.head
        else:
            cur = self.head
            while cur.next != self.head:
                cur = cur.next
            cur.next = node
            node.next = self.head

    def insert(self, index, item):
        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0
            cur = self.head
            while count < index - 1:
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        if self.head == None:
            print('空链表')
        else:
            cur = self.head
            pre = self.head
            if cur.item == item:
                while cur.next != self.head:
                    cur = cur.next
                cur.next = pre.next
                self.head = pre.next
            else:
                while cur.next.item != item:
                    cur = cur.next
                cur.next = cur.next.next

    def search(self, item):
        cur = self.head
        while cur.next is not None:
            if cur.item == item:
                return True
            else:
                cur = cur.next
        else:
            return False


link = SingleCycLink()
print('链表长度:', len(link))

link.trvel()

print(link.is_empty())

link.append(3)
link.add(2)
link.insert(1, 'hello')
link.append(6)
link.append(5)

print('链表长度:', len(link))
link.trvel()

link.add(5)
link.remove(4)
link.trvel()

四.双向链表

1.双向链表

**双向链表:**每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
在这里插入图片描述

2.双向链表的代码操作

"""
双向链表的封装
"""


class Node(object):
    """
    双向链表节点的封装
    """

    def __init__(self, element):
        self.element = element  # 数据域
        # 指针域
        self.next = None  # 指向后继节点的指针
        self.prev = None  # 指向前驱节点的指针

    def __str__(self):
        return self.element


class DuLinkList(object):
    """
    双向链表的封装
    """

    def __init__(self):
        self.head = None

    def is_empty(self):
        """判断双向链表是否为空"""
        return self.head == None

    def __len__(self):
        """获取双向链表的长度"""
        if self.is_empty():
            return 0
        cur = self.head
        linkLen = 0
        while cur:
            cur = cur.next
            linkLen += 1
        return linkLen

    def travel(self):
        """遍历链表元素"""
        if not self.is_empty():
            cur = self.head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)
        else:
            print("空链表")

    def add(self, item):
        """
        头部添加元素
            1. 先创建一个保存item值的节点
            2. 将新节点的链接域next指向头节点,即head指向的位置
            3. 将链表的头head指向新节点
        """
        node = Node(item)
        if self.is_empty():
            self.head = node
        else:
            node.next = self.head
            self.head.prev = node
            self.head = node

    def append(self, item):
        """
        尾部添加元素
            1. 先判断链表是否为空,若是空链表,则将head指向新节点
            2. 若不为空,则找到尾部,将尾节点的next指向新节点
        """
        node = Node(item)
        if self.is_empty():
            self.head = node
        else:
            cur = self.head
            while cur.next != None:
                cur = cur.next
            cur.next = node
            node.prev = cur

    def insert(self, index, item):
        """
        指定位置添加元素
            1. 若指定位置index为第一个元素之前,则执行头部插入
            2. 若指定位置超过链表尾部,则执行尾部插入
            3. 否则, 找到指定位置
        """
        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 当前位置
            cur = self.head
            while count < index - 1:
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node
            node.prev = cur
            cur.next.prev = node

    def remove(self, item):
        """
        删除指定元素的节点:
         1 2 3 4 5
         1. 如果删除的是头结点, 指针直接指向头结点的下一个节点;
         2. 如果删除的不是头结点, 一直循环, 知道找到要删除的节点元素;
        """
        if self.is_empty():
            return
        pre = None
        cur = self.head
        # 如果删除的是头结点, 指针直接指向头结点的下一个节点;
        if cur.element == item:
            self.head = self.head.next
        else:
            while cur:
                if cur.element != item:
                    pre = cur
                    cur = cur.next
                else:
                    # 判断删除的是否为尾部节点, 如果是, 则直接让pre.next指向为None;
                    if not cur.next:
                        pre.next = None
                        break

                    else:
                        # pre.next = pre.next.next
                        pre.next = cur.next
                        cur.next.prev = pre
                        break


    def search(self, item):
        cur = self.head
        while cur:
            if cur.element == item:
                return  True
            cur = cur.next
        else:
            return  False

if __name__ == '__main__':
    # 实例化双向链表对象
    link = DuLinkList()
    # 长度获取
    print("链表长度: ", len(link))
    # 遍历链表
    link.travel()
    print("链表是否为空? ", link.is_empty())

    # print("添加头结点:")
    # for item in range(5):
    #     link.add(item)  #  4 3 2 1 0
    #
    # # 长度获取
    # print("链表长度: ", len(link))
    # # 遍历链表
    # link.travel()
    # print("链表是否为空? ", link.is_empty())

    print("追加结点:")
    for item in range(5):
        link.append(item)  # 0  python 1  2 3 4

    # 长度获取
    print("链表长度: ", len(link))
    # 遍历链表
    link.travel()
    print("链表是否为空? ", link.is_empty())

    print("指定位置插入元素")
    link.insert(1, 'python')
    # 长度获取
    print("链表长度: ", len(link))
    # 遍历链表
    link.travel()
    print("链表是否为空? ", link.is_empty())

    print("删除元素")  # 0  python 1  2 3 4
    link.remove(4)
    link.travel()


    print("查找元素:")
    print(link.search(1))
    print(link.search(10))

在这里插入图片描述

五.链表实例

1.删除链表的倒数第N个节点

在这里插入图片描述

"""
   删除链表的倒数第k个元素
       1. 判断用户输入的合法性? link, n
       2. 如果输入数据合法
           1). p, q
           2). 让p指针和q指针之间的间距为k;
           3). 让p指针和q指针一块向后移动, 直到q.next为空的时候停止移动;
           4). p指针指向哪里? 指向要删除的元素的前一个节点 p.next = p.next.next

   """
from SingleLink import *
def deleteLinkElement(link, n):
    #1. 判断用户输入的合法性?
    if not link:
        return
    if  not link.head:
        return
    if n <= 0:
        return
    # 2.如果输入数据合法
    # 1).p, q
    p = link.head
    q = link.head
    # 2).让p指针和q指针之间的间距为k
    for item in range(n):
        q = q.next
    # 3).让p指针和q指针一块向后移动, 直到q.next为空的时候停止移动;
    while q.next:
        p = p.next
        q = q.next
    # 4).p指针指向哪里? 指向要删除的元素的前一个节点p.next = p.next.next
    p.next = p.next.next
    return link


if __name__ == '__main__':
    link = SingleLink()
    for num in range(5):
        link.append(num+1)
    link.trvel()
    deleteLinkElement(link, 2)
    link.trvel()

在这里插入图片描述

2.旋转链表

在这里插入图片描述

from SingleLink import *
def rorateRight(link, k):
    """
    向右移动k个元素(绕圈法):
        1. 判断录入数据的合法性? link是否存在? link是否为空? k是否为非负数.
        2. 如果数据合法;
            1). 访问到链表的最后
            2). 首尾相连
            3). 对k值进行处理:  k = k%len(link)
            4). 让指针移动到(len-k-1), 更新链表头结点
            5). 断开链表循环的部分
    :param link: 单链表对象
    :param k: 向右移动的数值
    :return:
    """
    # 1. 判断录入数据的合法性? link是否存在? link是否为空? k是否为非负数.
    if not link:
        return
    if not link.head:
        return
    if k < 0:
        return

    #  2. 如果数据合法;
    # 1).访问到链表的最后
    cur = link.head
    count = 1  # 链表的长度
    while cur.next:
        cur = cur.next
        count += 1
    # 2). 首尾相连
    cur.next = link.head

    # 3). 对k值进行处理:  k = k%len(link)
    k = k % count

    # 4).让指针移动到(len - k - 1),
    pre = link.head  # 最终指向要断开节点的前一个节点
    for i in range(count - k - 1):
        pre = pre.next

    # 更新链表头结点
    link.head = pre.next

    # 5).断开链表循环的部分
    pre.next = None
    return link


if __name__ == '__main__':
    link = SingleLink()
    for item in range(5):  # 1 2 3 4 5
        link.append(item + 1)
    link.trvel()


    print("测试".center(30, '*'))
    link1 = rorateRight(link, 8)
    link1.trvel()

在这里插入图片描述

3.分隔链表

在这里插入图片描述

from SingleLink import *

def Separarte(link, key):
    small_link = SingleLink()
    greater_link = SingleLink()
    if not link:
        return
    if not link.head:
        return
    len_link = len(link)
    f = link.head
    for i in range(len_link):
        if f.element >= key:
            greater_link.append(f.element)
            f = f.next
        else:
            small_link.append(f.element)
            f = f.next
    len_greater = len(greater_link)
    n = greater_link.head
    for a in range(len_greater):
        small_link.append(n.element)
        n = n.next
    small_link.traverse()
if __name__ == '__main__':
    link = SingleLink()
    ls = [1,4,3,2,5,2]
    for item in ls:
        link.append(item)
    link.traverse()
    Separarte(link, 3)

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值