Python线性表——单链表

1. 线性表简介

线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列。线性表的特征是在一个序列中,除了头尾元素,每个元素都有且只有一个直接前驱,有且只有一个直接后继,而序列头元素没有直接前驱,序列尾元素没有直接后继。

数据结构中常见的线性结构有数组、单链表、双链表、循环链表等。线性表中的元素为某种相同的抽象数据类型。可以是C语言的内置类型或结构体,也可以是C++自定义类型。

2. 数组

数组在实际的物理内存上也是连续存储的,数组有上界和下界。C语言中定义一个数组:

数组下标是从0开始的,a[0]对应第一个元素。其中,a[0]称为数组a的下界,a[6]称为数组a的上届。超过这个范围的下标使用数组,将造成数组越界错误
数组的特点是:数据连续,支持快速随机访问。
数组分为固定数组与动态数组。其中固定数组的大小必须在编译时就能够确认,动态数组允许在运行时申请数组内存。复杂点的数组是多维数组,多维数组实际上也是通过一维数组来实现的。在C语言中,可以通过malloc来分配动态数组,C++使用new。另外,C++的标准模板库提供了动态数组类型vector以及内置有固定数组类型array。

Python中list可以被认为是封装好的数组。

3. 单向链表

单向链表是链表的一种。链表由节点所构成,节点内含一个指向下一个节点的指针,节点依次链接成为链表。因此,链表这种数据结构通常在物理内存上是不连续的。链表的通常含有一个头节点,头节点不存放实际的值,它含有一个指针,指向存放元素的第一个节点。

show me the code

class Node():
    """
    单链表中的节点应该具有两个属性:val 和 next。
    val 是当前节点的值,
    next 是指向下一个节点的指针/引用。
    """

    def __init__(self, value):
        # 存放元素数据
        self.val = value
        # next是下一个节点的标识
        self.next = None

设计链表的实现

您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。

  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

show me the code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Author    : Young
@Email     : [email protected]
@site      : http://www.cnblogs.com/huang-yc/
@File      : linked_list2.py
@version   : 1.0
@Time      : 2019/4/5 11:06
Description about this file:

"""

class Node():
    """
    单链表中的节点应该具有两个属性:val 和 next。
    val 是当前节点的值,
    next 是指向下一个节点的指针/引用。
    """

    def __init__(self, value):
        # 存放元素数据
        self.val = value
        # next是下一个节点的标识
        self.next = None

class SingleLinkList():
    def __init__(self, node=None):
        # 头节点定义为私有变量
        self._head = node

    def is_empty(self):
        # 判断链表是否为空
        if self._head is None:
            return True
        else:
            return False

    def get(self, index: int) -> int:
        """
        获取链表中第 index 个节点的值。如果索引无效,则返回-1
        :param index: 索引值
        :return:
        """
        if self._head is None:
            return -1
        cur = self._head
        for i in range(index):
            if cur.next is None:
                return -1
            cur = cur.next
        return cur.val

    def length(self):
        """
        cur游标,用来移动遍历节点
        count用来计数
        :return: 返回链表的长度
        """
        cur = self._head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

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

    def add_at_head(self, val: int) -> None:
        """
        在头部添加一个节点
        :param val:
        :return: None
        """
        # 先创建一个保存item值的节点
        node = Node(val)
        # 判断链表是否为空
        if self._head is None:
            self._head = node
        else:
            # 将新节点的链接域next指向头节点,即_head指向的位置
            node.next = self._head
            # 将链表的头_head指向新节点
            self._head = node

    def add_at_tail(self, val: int) -> None or int:
        """
        在尾部添加一个节点
        :param item:
        :return:
        """
        node = Node(val)
        # 若链表为空,直接将该节点作为链表的第一个元素
        if self._head is None:
            self._head = node
        else:
            cur = self._head
            while cur.next is not None:
                cur = cur.next
            cur.next = node

    def add_at_index(self, index: int, val: int) -> None:
        """
        在指定位置pos添加节点
        pos从0开始
        :param index:
        :param val:
        :return:
        """
        # 若指定位置pos为第一个元素之前,则执行头部插入
        if index <= 0:
            self.add_at_head(val)
        # 若指定位置超过链表尾部,则执行尾部插入
        elif index >= self.length():
            self.add_at_tail(val)
        # 找到指定位置
        else:
            # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
            pre = self._head
            count = 0
            node = Node(val)
            # 在目标节点的前一位停下
            while count < (index - 1):
                count += 1
                pre = pre.next
            # 先将新节点node的next指向插入位置的节点
            node.next = pre.next
            # 将插入位置的前一个节点的next指向新节点
            pre.next = node

    def delete_at_index(self, index: int) -> None or int:
        """
        如果索引 index 有效,则删除链表中的第 index 个节点。
        :param index: 对应的索引值
        :return: -1表示为异常
        """
        pre = None
        cur = self._head
        if index is 0:
            self._head = None
        for i in range(index):
            if cur.next is None:
                # raise IndexError("越界")
                return -1
            pre = cur
            cur = pre.next
        else:
            pre.next = cur.next

    def search(self, val: int) -> True or False:
        """
        查找节点是否存在
        :param val: 节点的val值
        :return:
        """
        cur = self._head
        while cur is not None:
            if cur.val == val:
                return True
            else:
                cur = cur.next
        return False

if __name__ == '__main__':
    obj = SingleLinkList()
    obj.add_at_head(1)
    obj.add_at_tail(3)
    obj.add_at_index(1, 2)
    obj.travel()
    obj.delete_at_index(1)
    obj.travel()

链表与顺序表的对比

链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。

链表与顺序表的各种操作复杂度如下所示:

操作 链表 顺序表
访问元素 O(n) O(1)
在头部插入/删除 O(1) O(n)
在尾部插入/删除 O(n) O(1)
在中间插入/删除 O(n) O(n)

参考资料

https://www.cnblogs.com/QG-whz/p/5170147.html

https://blog.csdn.net/weixin_39881922/article/details/80470896

https://leetcode-cn.com/explore/learn/card/linked-list/193/singly-linked-list/741/

原文地址:https://www.cnblogs.com/huang-yc/p/10658447.html

时间: 2024-10-05 04:58:30

Python线性表——单链表的相关文章

JAVA实现具有迭代器的线性表(单链表)

一,迭代器的基本知识: 1,为什么要用迭代器?(迭代:即对每一个元素进行一次“问候”) 比如说,我们定义了一个ADT(抽象数据类型),作为ADT的一种实现,如单链表.而单链表的基本操作中,大部分需要用到依次遍历单链表中的每一个元素.一般而言,我们就是用for循环来实现遍历,这样,当你新增一个对单链表的操作并需要使用遍历时,你就得重新写一个for循环而实现遍历.那么,为什么不将迭代(遍历)作为一种基本的ADT操作(基本的ADT操作如:新增一个元素.删除一个元素)呢?于是,迭代器就出场了. 2,鉴于

线性表—单链表

.1.链式存储结构实现 单链表和双链表(这边讲单链表). 2.基础概念 a.结点:结点由数据域和地址域(链)两部分组成.而结点整体在效果上可以看作是该结点的地址(指针).这个地址域一般是后继元素的地址(即下一个结点的总体).所以最后一个元素的地址域为^,其表示空,即没有后续元素.b.单链表:每个结点只有一个地址域的线性链表称为单链表.c.双链表:每个结点有两个地址域的线性表链称为双链表,两个地址域分别指向前驱元素和后继元素. 3.单链表的实现 线性表接口LList: package com.cl

【 数据结构(C语言)】线性表——单链表

1.线性链表:用任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的也可以是不连续) #include <bits/stdc++.h> using namespace std; #define ElemType int #define Status int #define ERROR -1 #define OK 1 typedef struct LNode { ElemType data; struct LNode *next; }LNode ,*LinkList; LinkList

线性表--单链表(C++)

单链表演示图: 单链表结构体: struct Node { Node(const DataType& d)//节点的构造函数 :_data(d) ,_next(NULL) {} DataType _data;        //数据   struct Node *_next;    //指向下一个节点的指针 }; 带头结点和尾节点的单链表: 多一个Tail指针的好处就是很方便可以找到链表尾部,方便在尾部插入一个元素什么的. 下面我们用类来实现单链表: class SList { friend o

数据结构之 线性表---单链表的拆分

数据结构实验之链表五:单链表的拆分 Time Limit: 1000MS Memory limit: 65536K 题目描述 输入N个整数顺序建立一个单链表,将该单链表拆分成两个子链表,第一个子链表存放了所有的偶数,第二个子链表存放了所有的奇数.两个子链表中数据的相对次序与原链表一致. 输入 第一行输入整数N;: 第二行依次输入N个整数. 输出 第一行分别输出偶数链表与奇数链表的元素个数: 第二行依次输出偶数子链表的所有数据: 第三行依次输出奇数子链表的所有数据. 示例输入 10 1 3 22

数据结构之 线性表---单链表操作A (删除链表中的指定元素)

数据结构上机测试2-1:单链表操作A Time Limit: 1000MS Memory limit: 4096K 题目描述 输入n个整数,先按照数据输入的顺序建立一个带头结点的单链表,再输入一个数据m,将单链表中的值为m的结点全部删除.分别输出建立的初始单链表和完成删除后的单链表. 输入 第一行输入数据个数n: 第二行依次输入n个整数: 第三行输入欲删除数据m. 输出 第一行输出原始单链表的长度: 第二行依次输出原始单链表的数据: 第三行输出完成删除后的单链表长度: 第四行依次输出完成删除后的

数据结构 线性表—单链表

本文只要实现单链表的初始化.插入(尾插.头插.任意位置插入).删除(尾删.头删.删除指定元素).查找等. 定义单链表 typedef int DataType; typedef struct LinkNode {  DataType data;  struct LinkNode *next; }LinkNode, *pLinkNode, *pList; 实现单链表的所有接口: void InitLinkList(pList* pHead);//单链表的初始化 void Destroy(pList

数据结构之 线性表---单链表的操作B(先逆序+再删除重复元素)

数据结构上机测试2-2:单链表操作B Time Limit: 1000MS Memory limit: 65536K 题目描述 按照数据输入的相反顺序(逆位序)建立一个单链表,并将单链表中重复的元素删除(值相同的元素只保留最后输入的一个). 输入 第一行输入元素个数n: 第二行输入n个整数. 输出 第一行输出初始链表元素个数: 第二行输出按照逆位序所建立的初始链表: 第三行输出删除重复元素后的单链表元素个数: 第四行输出删除重复元素后的单链表. 示例输入 10 21 30 14 55 32 63

数据结构(一)线性表单链表试题

题目 快速找到未知长度的单链表的中间节点 解决思路 (一)使用一个指针,先索引一遍获取总长度,再取长度一半去循环获取到中间值 算法复杂度:O(L)+O(L/2) = O(3L/2) (二)使用两个指针,快指针和慢指针,快指针一次向前走2格,慢指针一次走一格,当快指针走完全程,慢指针正好走在中间 算法复杂度:O(L/2) 方法二:代码实现 //快速查找中间元素 int FindMidEle(LinkList L, Elemtype *e) { LinkList search, middle; //