数据结构与算法——链表——Celia

单链表及基本操作

概念补充:后继结点,即后一个邻结点

  1. 创建一个节点
# 单链表及节点定义代码
# 节点中需要保存它的数据和下一个链接地址
class Node(object):
    """节点"""
    def __init__(self, elem):
        self.elem = elem+
        
        self.next = None  # 先不指向任何区域
  1. 创建一个链表
class SingleLinkList(object):
    """单链表"""
    # 链表中必须存在一个(对象)属性,指向第一个节点
    # 设置默认参数为空,为让顾客没输入第一个节点时也可以运行
    def __init__(self, node):
        self.__head = None
  1. 一些链表相关操作:
    宗旨:不要先打断原有链表,先对待操作的新节点进行操作
    ① 判断是否为空链表
    # 链表是否为空(对具体对象的操作是对象方法而不是类方法)
    def is_empty(self):
        """链表是否为空"""
        return self.__head == None

② 计算链表长度

    def length(self):
        """链表长度(节点数目)"""
        # cur游标用来移动遍历节点
        cur = self.__head  # 建立cur游标=起始节点
        # count记录数量
        count = 0  # 若设置为1则还需要额外考虑空链表情况
        while cur != None:
            count += 1
            cur = cur.next
        return count

③ 遍历整个链表

    def travel(self):
        """遍历整个链表(需要定义一个游标cur来记录当前位置)"""
        cur = self.__head
        while cur != None:
            print(cur.elem, end="")
            cur = cur.next

④ 在链表头部插入节点:

def add(self, item):
    """链表头部添加元素(放入节点),头插法"""
    node = Node(item)  # 待插入的新节点
    # 注意这里指的不是node节点的下一节点,而是其next区域
    node.next = self.__head  # 让新节点的next区域等于原head区域(插入图片)

在这里插入图片描述

def add(self, item):
    """链表头部添加元素(放入节点),头插法"""
    node = Node(item)  # 待插入的新节点
    # 注意这里指的不是node节点的下一节点,而是其next区域
    node.next = self.__head  # 让新节点的next区域等于原head区域(插入图片)
    self.__head = node

在这里插入图片描述
原有节点指向新节点
⑤ 在链表尾部插入节点:

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.next = node

⑥ 指定位置添加元素

def insert(self, pos, item):
    """指定位置添加元素(在哪个位置、添加哪个节点)
    :param pos从0开始
    """
    if pos <= 0:
        self.add(item)
    elif pos > (self.length()-1):
        self.append(item)
    else:
        count = 0
        pre = self.__head  # 定义一个游标
        while count < (pos-1):
            count += 1
            pre = pre.next
        # 当循环退出后,pre指向pos-1位置
        node = Node(item)
        node.next = pre.next
        pre.next = node

⑦ 查找节点是否存在

def search(self, item):
    """查找节点是否存在"""
    cur = self.__head
    while cur != None:
        if cur.elem == item:
            return True
        else:
            cur = cur.next
    return False

⑧删除节点
有两种情况:两个游标和一个游标
在这里插入图片描述
两个游标的情况:

def remove(self, item):
    """删除节点(删掉元素集而不是位置)"""
    cur = self.__head
    pre = None
    while cur != None:
        if cur.elem == item:
            # 先判断此节点是否是头节点
            # 头节点
            if cur == self.__head:
                self.__head = cur.next
            else:
                pre.next = cur.next  # 验证删头/尾节点是否能够删除
            break  # 否则进入死循环
        else:
            # 保持pre游标始终在cur游标前面
            pre = cur
            cur = cur.next
    return False

补充说明:
在这里插入图片描述
self.__head指的是其指向的100node

总体及运行结果:

# 单链表及节点定义代码
# 节点中需要保存它的数据和下一个链接地址
class Node(object):
    """节点"""
    def __init__(self, elem):
        self.elem = elem
        self.next = None  # 先不指向任何区域



class SingleLinkList(object):
    """单链表"""
    # 链表中必须存在一个(对象)属性,指向第一个节点
    # 设置默认参数为空,为让顾客没输入第一个节点时也可以运行
    def __init__(self, node):
        self.__head = None

    # 链表是否为空(对具体对象的操作是对象方法而不是类方法)
    def is_empty(self):
        """链表是否为空"""
        return self.__head == None

    def length(self):
        """链表长度(节点数目)"""
        # cur游标用来移动遍历节点
        cur = self.__head  # 建立cur游标=起始节点
        # count记录数量
        count = 0  # 若设置为1则还需要额外考虑空链表情况
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历整个链表(需要定义一个游标cur来记录当前位置)"""
        cur = self.__head
        while cur != None:
            print(cur.elem, end="")
            cur = cur.next

        print("")  # 遍历后换行



    def add(self, item):
        """链表头部添加元素(放入节点),头插法"""
        node = Node(item)  # 待插入的新结点
        # 注意这里指的不是node节点的下一节点,而是其next区域
        node.next = self.__head  # 让新节点的next区域等于原head区域(插入图片)
        self.__head = node



    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.next = node



    def insert(self, pos, item):
        """指定位置添加元素(在哪个位置、添加哪个节点)
        :param pos从0开始
        """
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            count = 0
            pre = self.__head  # 定义一个游标
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 当循环退出后,pre指向pos-1位置
            node = Node(item)
            node.next = pre.next
            pre.next = node

    def remove(self, item):
        """删除节点(删掉元素集而不是位置)"""
        cur = self.__head
        pre = None
        while cur != None:  # 往后移动的调件
            if cur.elem == item:
                # 先判断此节点是否是头节点
                # 头节点
                if cur == self.__head:
                    self.__head = cur.next
                else:
                    pre.next = cur.next  # 验证删头/尾节点是否能够删除
                break  # 否则进入死循环
            else:
                # 保持pre游标始终在cur游标前面
                pre = cur
                cur = cur.next
        return False


    def search(self, item):
        """查找节点是否存在"""
        cur = self.__head
        while cur != None:
            if cur.elem == item:
                return True
            else:
                cur = cur.next
        return False


"""
node = Node(100)
single_obj = SingleLinkList(node)
single_obj.travel()
"""

if __name__ == "__main__":
    ll = SingleLinkList(1)
    print((ll.is_empty()))
    print((ll.length()))

    ll.append(1)
    print((ll.is_empty()))
    print(ll.length())

    ll.append(2)
    ll.append(3)
    ll.append(4)
    ll.add(8)
    ll.insert(-1, 9)  # 小于0都视为从头开始,9、8、1、2、3、4
    ll.travel()
    ll.insert(3, 100)  # 索引计数从0开始,9、8、1、100、2、3、4
    ll.travel()
    ll.insert(10, 200)  # 9、8、1、100、2、3、4、200
    ll.travel()
    ll.remove(100)
    ll.travel()
    ll.remove(9)
    ll.travel()
    ll.remove(200)
    ll.travel()
True
0
False
1
981234
981100234
981100234200
981234200
81234200
81234

链表与顺序表的对比

在这里插入图片描述

双向链表基本操作

双向链表
在这里插入图片描述
引入概念:前驱结点、后继结点
基本操作
① 结点创建

class Node(object):
    """结点"""
    def __init__(self, item):
        self.elem = item
        self.next = None
        self.prev = None


② 链表创建

class DoubleLinkList(object):  # 不涉及pre游标的也可以直接继承自单链表
    def __init__(self, node):
        self.__head = None

③判断链表是否为空

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

④ 链表长度计算

def length(self):
    """链表长度(节点数目)"""
    # cur游标用来移动遍历节点
    cur = self.__head  # 建立cur游标=起始节点
    # count记录数量
    count = 0  # 若设置为1则还需要额外考虑空链表情况
    while cur != None:
        count += 1
        cur = cur.next
    return count

⑤ 遍历

def travel(self):
    """遍历整个链表(需要定义一个游标cur来记录当前位置)"""
    cur = self.__head
    while cur != None:
        print(cur.elem, end="")
        cur = cur.next

    print("")  # 遍历后换行

⑥ 头部添加元素

def add(self, item):
    """链表头部添加元素(放入节点),头插法"""
    node = Node(item)  # 待插入的新节点
    # 注意这里指的不是node节点的下一节点,而是其next区域
    node.next = self.__head  # 让新节点的next区域等于原head区域(插入图片)
    self.__head = node
    node.next.prev = node  # 顺序不唯一

⑦ 尾部添加元素

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.next = node
        node.prev = cur

⑧ 指定位置添加元素(结点)
操作方法举例(两种):
在这里插入图片描述
在这里插入图片描述

def insert(self, pos, item):
    """指定位置添加元素(在哪个位置、添加哪个节点)
    :param pos从0开始
    """
    if pos <= 0:
        self.add(item)
    elif pos > (self.length()-1):
        self.append(item)
    else:
        cur = self.__head
        count = 0
        while count < pos:
            count += 1
            cur = cur.next
        # 当循环退出后,pre指向pos位置
        node = Node(item)
        node.next = cur
        node.prev = cur.prev
        cur.prev.next = node
        cur.prev = node

⑨ 删除结点

在这里插入图片描述

def remove(self, item):
    """删除节点(删掉元素集而不是位置)"""
    cur = self.__head
    while cur != None:
        if cur.elem == item:
            # 先判断此节点是否是头节点
            # 头节点
            if cur == self.__head:
                self.__head = cur.next
                if cur.next != None:
                    # 判断链表是否只有一个结点
                    cur.next.prev = None  # 若是,则cur.next是None,没有prev
            else:
                cur.prev.next = cur.next
                if cur.next:
                    cur.next.prev = cur.prev
            break  # 否则进入死循环
        else:
            cur = cur.next

⑩ 查找结点是否存在

def search(self, item):
    """查找节点是否存在"""
    cur = self.__head
    while cur != None:
        if cur.elem == item:
            return True
        else:
            cur = cur.next
    return False

运算结果:

if __name__ == "__main__":
    dll = DoubleLinkList(1)
    print((dll.is_empty()))
    print((dll.length()))

    dll.append(1)
    print((dll.is_empty()))
    print(dll.length())

    dll.append(2)
    dll.append(3)
    dll.append(4)
    dll.add(8)
    dll.insert(-1, 9)
    dll.travel()
    dll.insert(3, 100)
    dll.travel()
    dll.insert(10, 200)
    dll.travel()
    dll.remove(100)
    dll.travel()
    dll.remove(9)
    dll.travel()
    dll.remove(200)
True
0
False
1
981234
981100234
981100234200
981234200
81234200
81234

单向循环链表

一. 遍历和求长度

单向循环链表:尾结点指针区next指向头结点
在这里插入图片描述

二. 添加元素

宗旨尽量先动要插入的结点,不先动原有结点
1.在头部添加元素
1.将node插入头部
在这里插入图片描述

node.next = self.__head (self.__head指的是100结点,此操作让400的next指向100)
self.__head = node (让head指向400)

注意
1)上述顺序不能颠倒,否则后部分链表会丢失
2)这里self.__head是一个 “前部分为空+next” 结点,本身的意思就是“next”形式的
3)self.__head是真实存在的结点

2.让尾部指向头部
由于需要找到尾结点,所以需要有一个遍历的过程。有两种方法:先遍历找到尾结点再插入头结点 or 先插入再遍历

方法一:先插入后遍历(不太好理解)
要遍历,就先设计游标cur:
1)由于终止条件原来是:cur.next = self.__head ,所以找到 “cur.next = node.next”也就找到了尾结点( 即都指向100结点)
在这里插入图片描述
方法2:先遍历找到尾结点再插入
1)当 cur.next = self.__head 则找到了尾结点,所以

while cur.next != self.__head
    cur = cur.next

2)然后

node.next = self.__head
self.__head = node
cur.next = node # 使尾结点指向node,
# 或者写成cur.next = self.__head

3)检查特殊情况(空链表、、)
空链表:若判断为空,则让head指向添加的结点,并让它再指向自身

if self.is_empty():
    self.__head = node
    node.next = node
else

只有一个结点
原代码依然可行,不用修改

2.在尾部添加元素

  1. 将node插入尾部
    两种方法
# 先动node
node.next = cur.next
cur.next = node

或者

# 先动链表
cur.next = node
node.next = self.__head
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值