「数据结构与算法之链表(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对象中 ...
随机推荐
- TCP/IP学习笔记9--以太网之基本概念1: 分类,连接方式
时间是变化的财富.时钟模仿它,却只有变化而无财富. -- 泰戈尔 以太网(Ethernet)一词源于Ether(以太), 是介质的意思.在爱因斯坦哥们提出量子力学之前,人们普遍认为宇宙空间充满以太,并 ...
- 网页授权access_token,基础支持access_token,jsapi_ticket
微信开发中网页授权access_token与基础支持的access_token异同 问题1:网页授权access_token与分享的jssdk中的access_token一样吗? 答:不一样.网页授权 ...
- [转帖]运维必读:Linux 的内存分页管理
运维必读:Linux 的内存分页管理 https://cloud.tencent.com/developer/article/1356431 内存是计算机的主存储器.内存为进程开辟出进程空间,让进程在 ...
- Servlet 表单及上传文件
// 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestServletForm.java package com.test; impo ...
- 《Mysql - 幻读》
一:准备 - 为了深入了解幻读,准备数据. CREATE TABLE `t` ( `id` ) NOT NULL, `c` ) DEFAULT NULL, `d` ) DEFAULT NULL, PR ...
- Windows终端命令行工具Cmder
在IT这一行,大部分情况下都是推荐大家使用Linux或者类Unix操作系统去编程,Linux作为一代优秀的操作系统,已经人尽皆知,在IT行业已经成为核心.有条件的大佬都选择了使用mac编程,最优秀的莫 ...
- 数据结构之链表(LinkedList)(三)
数据结构之链表(LinkedList)(二) 环形链表 顾名思义 环形列表是一个首尾相连的环形链表 示意图 循环链表的特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活. 看一 ...
- 浅谈javascript中变量作用域和内存(1)
先理解两个概念:基本类型和引用类型的值 1.基本类型和引用类型的值 (1)定义: 基本类型:指简单的数据段,比如按值访问的js五种基本数据类型undefined.null.boolean.number ...
- 什么是Familywise Error Rate
1.什么是Familywise Error Rate(FWE or FWER) 定义:在一系列假设检验中,至少得出一次错误结论的概率. 换句话说,是造成至少一次Type I Error的概率.术语FW ...
- mybatisplus 使用案例
案例地址 https://github.com/qixianchuan/SpringBootQD/tree/master/mybatisplus