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 : hyc554@outlook.com
@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/

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

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

    一,迭代器的基本知识: 1,为什么要用迭代器?(迭代:即对每一个元素进行一次“问候”) 比如说,我们定义了一个ADT(抽象数据类型),作为ADT的一种实现,如单链表.而单链表的基本操作中,大部分需要用 ...

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

    数据结构上机测试2-2:单链表操作B Time Limit: 1000MS Memory limit: 65536K 题目描述 按照数据输入的相反顺序(逆位序)建立一个单链表,并将单链表中重复的元素删 ...

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

    数据结构上机测试2-1:单链表操作A Time Limit: 1000MS Memory limit: 4096K 题目描述 输入n个整数,先按照数据输入的顺序建立一个带头结点的单链表,再输入一个数据 ...

  4. python实现数据结构单链表

    #python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" ...

  5. Python数据结构之单链表

    Python数据结构之单链表 单链表有后继结点,无前继结点. 以下实现: 创建单链表 打印单链表 获取单链表的长度 判断单链表是否为空 在单链表后插入数据 获取单链表指定位置的数据 获取单链表指定元素 ...

  6. C语言 严蔚敏数据结构 线性表之链表实现

    博主最近在考成都大学皇家计算机科学与技术专业,复习专业课数据结构,正好学习到线性结构中的线性表用链表这种存储结构来实现. 首先,数据结构包括1.数据的操作2.逻辑结构3.存储结构(数据结构三要素. 直 ...

  7. C数据结构 : 线性表 与 链表

    一.线性表 一般表现为数组,使用一组地址连续的存储单元依次存储数据元素,如图: 它具有如下特点: 长度固定,必须在分配内存之前确定数组的长度. 存储空间连续,即允许元素的随机访问. 存储密度大,内存中 ...

  8. Python 之简易单链表

    单链表的基本要素有 2 个,数据项和连接项.这两项在 Python 中可以通过对象及其属性来实现. class Node: def __init__ (self, data): self.data = ...

  9. python 数据结构之单链表的实现

    链表的定义: 链表(linked list)是由一组被称为结点的数据元素组成的数据结构,每个结点都包含结点本身的信息和指向下一个结点的地址.由于每个结点都包含了可以链接起来的地址信息,所以用一个变量就 ...

随机推荐

  1. centos7搭建gitlab服务器、汉化

    1.下载rpm安装包 https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-8.8.5-ce.1.el7.x86_64.rp ...

  2. vue---由nextTick原理引出的js执行机制

    最开始查看nextTick这个方法的时候,眼瞎看成了nextClick...我还在疑问难道是下一次click之后处理事件... 然后用这个方法的时候,就只知道是用在DOM更新之后调用回调方法. 这时就 ...

  3. Java转换流、缓冲流、流操作规律整理

    转换流 1.1                OutputStreamWriter类 OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字 ...

  4. matlab中cumsum函数

    matlab中cumsum函数通常用于计算一个数组各行的累加值.在matlab的命令窗口中输入doc cumsum或者help cumsum即可获得该函数的帮助信息. 格式一:B = cumsum(A ...

  5. windows下使用curl命令 && 常用curl命令

    什么是curl命令? curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被广泛应用在Unix.多种Linux发行版中,并且有DOS和Win32.Win64下的移植版本. 如何在windo ...

  6. HDU 5965(三行扫雷 dp)

    题意是在一个 3 行 n 列的图上进行扫雷,中间一行没有雷,且中间一行的每一格都会显示周围的雷数,问根据已知的雷数在上下两行设置地雷的方法数. 分析知每一列所填雷数的和与周围的雷数有关,但每列具体的填 ...

  7. [物理学与PDEs]第1章习题4 偶极子的极限电势

    对在 $P_0$ 及 $P_1$ 处分别置放 $-q$ 及 $+q$ 的点电荷所形成的电偶极子, 其偶极距 ${\bf m}=q{\bf l}$, ${\bf l}=\vec{P_0P_1}$. 试证 ...

  8. luogu P5300 [GXOI/GZOI2019]与或和

    传送门 题目涉及按位与以及按位或运算,所以可以拆位考虑,枚举某个二进制位,然后某个位置如果那个数的第\(i\)位是\(0\)就放\(0\),否则放\(1\),这一位的贡献就是位运算后值为\(1\)的子 ...

  9. 【转】【Linux】Swap与Memory

    背景介绍 Memory指机器物理内存,读写速度低于CPU一个量级,但是高于磁盘不止一个量级.所以,程序和数据如果在内存的话,会有非常快的读写速度.但是,内存的造价是要高于磁盘的,且内存的断电丢失数据也 ...

  10. 更改Ubuntu默认python版本的方法

    当你安装 Debian Linux 时,安装过程有可能同时为你提供多个可用的 Python 版本,因此系统中会存在多个 Python 的可执行二进制文件.一般Ubuntu默认的Python版本都为2. ...