「数据结构与算法之链表(Python)」(四)
什么是链表
顺序表的储存分为一体式结构和分离式结构,但总的来说存储数据的内存是一块连续的单元,每次申请前都要预估所需要的内存空间大小。这样就不能随意的增加我们需要的数据了。链接就是为了解决这个问题。它的数据存储方式是每插入一个数据,就在内存中申请一块存储空间来保存,那么新增加的数据如何和之前的数据保持关联呢?解决方法就是在原来的数据内存里保存新增加的数据的内存地址,这样就相当于用“一根线”把它们都串了起来,因此每次新插入一个数据,就要在内存中申请两个连续的空间,一个用来储存数据,一个用来储存下一个数据的地址。寻址方式就是从第一个数据开始依次往下寻找。
(ps:图画的有点丑2333)
另外,链表和顺序表统称为线性表。
同时,我们需要一个内存空间,用来保存链表第一个数据的地址,因此,完整的结构应该是

了解是链表的概念后,我们就要想办法来实现它,那么,用什么方式实现呢?
我们知道,链表的实现需要把数据以及所支持的结构放到一起形成一个整体,这样才构成链表。这时就要用到面向对象中类的概念了。但因为链表其中还保存数据地址这个功能,我们就先要来学习先python中有关变量地址的一点知识。
首先,我们知道,在其他语言,类似C语言中,表示地址用的是指针,但在python中根本没有指针这个类型,那我们要如何操作跟地址有关的概念呢?其实,python中定义变量和C语言是不一样的,在C语言中定义一个变量前需要声明变量的类型,例如:int c = 1。这样就相当于在内存中划出一块地方用来存放整数1。但在python中,为什么我们可以不用声明变量的类型就可以定义变量了呢?这是因为我们定义的那个变量保存的不是我们想要赋予变量的值,而是存放该值的内存地址,举个例子,如图:
定义a = 10 b = 20,那么在内存中的存储方式为

当进行交换后,a, b = b, a,此时:

因此保存变量的的那块内存中的值根本没有变化,变化的是a和b中所指向的内存地址。
把这种思想用到我们要实现的类中来,也就是类中存在两个内存,一个存放数据,一个存放下个节点的地址。当实例化一个对象后,elem保存数据的值,而next保存下一个对象的地址。如图:

代码实现
# coding:utf-8
class SingleNode(object):
"""单链表的结点"""
def __init__(self,elem):
# _item存放数据元素
self.elem = elem
# _next是下一个节点的标识
self.next = None class SingleLinkList(object):
"""单链表"""
def __init__(self, node=None):
self.__head = node def is_empty(self):
"""判断链表是否为空"""
return self.__head == None def length(self):
"""链表长度"""
# cur初始时指向头节点
cur = self.__head
count = 0
# 尾节点指向None,当未到达尾部时
while cur != None:
count += 1
# 将cur后移一个节点
cur = cur.next
return count def travel(self):
"""遍历链表"""
cur = self.__head
while cur != None:
print(cur.elem, end=" ")
cur = cur.next def add(self, elem):
"""头部添加元素"""
# 先创建一个保存item值的节点
node = SingleNode(elem)
# 将新节点的链接域next指向头节点,即__head指向的位置
node.next = self.__head
# 将链表的头_head指向新节点
self.__head = node def append(self, elem):
"""尾部添加元素"""
node = SingleNode(elem)
# 先判断链表是否为空,若是空链表,则将__head指向新节点
if self.is_empty():
self.__head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = node def insert(self, pos, elem):
"""指定位置添加元素"""
# 若指定位置pos为第一个元素之前,则执行头部插入
if pos <= 0:
self.add(elem)
# 若指定位置超过链表尾部,则执行尾部插入
elif pos > (self.length() - 1):
self.append(elem)
# 找到指定位置
else:
node = SingleNode(elem)
count = 0
# pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
pre = self.__head
while count < (pos - 1):
count += 1
pre = pre.next
# 先将新节点node的next指向插入位置的节点
node.next = pre.next
# 将插入位置的前一个节点的next指向新节点
pre.next = node def remove(self, elem):
"""删除节点"""
cur = self.__head
pre = None
while cur != None:
# 找到了指定元素
if cur.elem == elem:
# 如果第一个就是删除的节点
if cur == self.__head:
# 将头指针指向头节点的后一个节点
self.__head = cur.next
else:
# 将删除位置前一个节点的next指向删除位置的后一个节点
pre.next = cur.next
break
else:
# 继续按链表后移节点
pre = cur
cur = cur.next def search(self, elem):
"""链表查找节点是否存在,并返回True或者False"""
cur = self.__head
while cur != None:
if cur.elem == elem:
return True
cur = cur.next
return False # 测试
if __name__ == "__main__":
ll = SingleLinkList()
ll.add(1)
ll.add(2)
ll.append(3)
ll.insert(2, 4)
print("length:",ll.length())
ll.travel()
print(ll.search(3))
print(ll.search(5))
ll.remove(1)
print("length:",ll.length())
ll.travel()

双向链表
# coding:utf-8 class Node(object):
"""节点"""
def __init__(self, elem):
self.elem = elem
self.prev = None
self.next = None class DoubleLinkList(object):
"""单链表"""
def __init__(self, node=None):
self.__head = node def is_empty(self):
"""判断链表是否为空"""
return self.__head == None def length(self):
"""链表长度"""
# cur初始时指向头节点
cur = self.__head
count = 0
# 尾节点指向None,当未到达尾部时
while cur != None:
count += 1
# 将cur后移一个节点
cur = cur.next
return count def travel(self):
"""遍历链表"""
cur = self.__head
while cur != None:
print(cur.elem, end=" ")
cur = cur.next def add(self, elem):
"""头部添加元素"""
# 先创建一个保存item值的节点
node = Node(elem)
# 将新节点的链接域next指向头节点,即__head指向的位置
node.next = self.__head
# 将链表的头_head指向新节点
self.__head = node
self.__head.prev = node def append(self, elem):
"""尾部添加元素"""
node = Node(elem)
# 先判断链表是否为空,若是空链表,则将__head指向新节点
if self.is_empty():
self.__head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = node
node.prev = cur def insert(self, pos, elem):
"""指定位置添加元素"""
# 若指定位置pos为第一个元素之前,则执行头部插入
if pos <= 0:
self.add(elem)
# 若指定位置超过链表尾部,则执行尾部插入
elif pos > (self.length() - 1):
self.append(elem)
# 找到指定位置
else:
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
node = Node(elem)
node.next = cur
node.prev = cur.prev
cur.prev.next = node # cur.prev = node
cur.prev = node # cur.prev.next = node def remove(self, elem):
"""删除节点"""
cur = self.__head
while cur != None:
# 找到了指定元素
if cur.elem == elem:
# 如果第一个就是删除的节点
if cur == self.__head:
# 将头指针指向头节点的后一个节点
self.__head = cur.next
if cur.next: # 判断链表是不是只有一个结点
cur.next.prev = None
else:
# 将删除位置前一个节点的next指向删除位置的后一个节点
cur.prev.next = cur.next
if cur.next: # 判断该结点是不是链表最后一个
cur.next.prev = cur.prev
break
else:
# 继续按链表后移节点
cur = cur.next def search(self, elem):
"""链表查找节点是否存在,并返回True或者False"""
cur = self.__head
while cur != None:
if cur.elem == elem:
return True
cur = cur.next
return False # 测试
if __name__ == "__main__":
d = DoubleLinkList()
d.add(1)
d.add(2)
d.append(3)
d.insert(2, 4)
print("length:",d.length())
d.travel()
print(d.search(3))
print(d.search(5))
d.remove(2)
print("length:",d.length())
d.travel()
「数据结构与算法之链表(Python)」(四)的更多相关文章
- 「数据结构与算法(Python)」(一)
算法的提出 算法的概念 算法是计算机处理信息的本质,因为计算机程序本质上是一个算法来告诉计算机确切的步骤来执行一个指定的任务.一般地,当算法在处理信息时,会从输入设备或数据的存储地址读取数据,把结果写 ...
- C语言 - 基础数据结构和算法 - 企业链表
听黑马程序员教程<基础数据结构和算法 (C版本)>,照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友可 ...
- C语言 - 基础数据结构和算法 - 单向链表
听黑马程序员教程<基础数据结构和算法 (C版本)>,照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友可 ...
- 「数据结构与算法(Python)」(二)
顺序表 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等.一组数据中包含的元素个数可能发生变化(可以增加或删除元素). 对 ...
- 「数据结构与算法(Python)」(三)
栈结构实现 栈可以用顺序表实现,也可以用链表实现. 栈的操作 Stack() 创建一个新的空栈 push(item) 添加一个新的元素item到栈顶 pop() 弹出栈顶元素 peek() 返回栈顶元 ...
- 用Python实现的数据结构与算法:链表
一.概述 链表(linked list)是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接(参考 <算法:C语言实现>). 根据结构的不同,链表可以 ...
- python基础下的数据结构与算法之链表
一.链表的定义 用链接关系显式表示元素之间顺序关系的线性表称为链接表或链表. 二.单链表的python实现 class Node(object): """定义节点&quo ...
- Python实现的数据结构与算法之链表详解
一.概述 链表(linked list)是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接.根据结构的不同,链表可以分为单向链表.单向循环链表.双向链表.双向循 ...
- Java数据结构和算法之链表
三.链表 链结点 在链表中,每个数据项都被包含在‘点“中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LINK对象中 ...
随机推荐
- 《ucore lab1 exercise6》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 题目:完善中断初始化和处理 请完成编码工作和回答如下问题: 中断描述符表(也可简称为保护模式下的中断向量表)中一个表项占多少字节?其中哪几位代表 ...
- 关于启动kylin报Failed to find metadata store by url: kylin_metadata@hbase的问题解决
一.出问题的原因 昨天因为项目需要,要将cloudera集群改成高可用,没想到失败了,当时因为冲动手动删了几个hdfs实例的原因,导致退不到原来的状态,折腾了一天,最后终于退回了非HA的集群,但是hd ...
- [转帖]Linux下主机间文件传输命令
Linux下主机间文件传输命令 https://yq.aliyun.com/articles/53631?spm=a2c4e.11155435.0.0.580ce8ef4Q9uzs SCP命令: ...
- PAT(B) 1053 住房空置率(Java)统计
题目链接:1053 住房空置率 (20 point(s)) 题目描述 在不打扰居民的前提下,统计住房空置率的一种方法是根据每户用电量的连续变化规律进行判断.判断方法如下: 在观察期内,若存在超过一半的 ...
- Docker 学习笔记(四):问题日志
一.Docker-Compose 容器组开机重启失败 Docker-Compose 的 depends_on 参数在 docker 中没有对应. 重启电脑后,容器的重启过程只由 docker 控制,而 ...
- CentOS 6.9安装配置nmon
nmon是一款开源的性能监控工具,用于监控CentOS系统的资源消耗信息,并能把结果输出到文件中,然后通过nmon_analyser性能报告分析器生成数据分析报表. 一.安装nmon: 1. 配置ep ...
- js 遍历树的层级关系的实现
1.遍历树的层级关系 1)先整理数据 2)找到id和数据的映射关系 3)然后找到父节点的数据,进行存储 test() { const list = [ { id: ", parentId: ...
- robot framework 的关键字Continue For Loop 用法
Continue For Loop关键字就是python的continue的意思,跳出本层循环,继续执行下一个循环. 我先举个栗子: :FOR ${index} IN RANGE 5 ...
- $.ajaxSetup()与$.ajax()区别
ajaxSetup()其使用方法与ajax()并无区别,只是在其之后的ajax()不用再重复添加相同参数,节省了代码量. 附:API中关于jQuery.ajaxSetup([options])的描述和 ...
- Fortify漏洞之Sql Injection(sql注入)
公司最近启用了Fortify扫描项目代码,报出较多的漏洞,安排了本人进行修复,近段时间将对修复的过程和一些修复的漏洞总结整理于此! 本篇先对Fortify做个简单的认识,同时总结一下sql注入的漏洞! ...