什么是链表

顺序表的储存分为一体式结构和分离式结构,但总的来说存储数据的内存是一块连续的单元,每次申请前都要预估所需要的内存空间大小。这样就不能随意的增加我们需要的数据了。链接就是为了解决这个问题。它的数据存储方式是每插入一个数据,就在内存中申请一块存储空间来保存,那么新增加的数据如何和之前的数据保持关联呢?解决方法就是在原来的数据内存里保存新增加的数据的内存地址,这样就相当于用“一根线”把它们都串了起来,因此每次新插入一个数据,就要在内存中申请两个连续的空间,一个用来储存数据,一个用来储存下一个数据的地址。寻址方式就是从第一个数据开始依次往下寻找。

(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)」(四)的更多相关文章

  1. 「数据结构与算法(Python)」(一)

    算法的提出 算法的概念 算法是计算机处理信息的本质,因为计算机程序本质上是一个算法来告诉计算机确切的步骤来执行一个指定的任务.一般地,当算法在处理信息时,会从输入设备或数据的存储地址读取数据,把结果写 ...

  2. C语言 - 基础数据结构和算法 - 企业链表

    听黑马程序员教程<基础数据结构和算法 (C版本)>,照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友可 ...

  3. C语言 - 基础数据结构和算法 - 单向链表

    听黑马程序员教程<基础数据结构和算法 (C版本)>,照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友可 ...

  4. 「数据结构与算法(Python)」(二)

    顺序表 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等.一组数据中包含的元素个数可能发生变化(可以增加或删除元素). 对 ...

  5. 「数据结构与算法(Python)」(三)

    栈结构实现 栈可以用顺序表实现,也可以用链表实现. 栈的操作 Stack() 创建一个新的空栈 push(item) 添加一个新的元素item到栈顶 pop() 弹出栈顶元素 peek() 返回栈顶元 ...

  6. 用Python实现的数据结构与算法:链表

    一.概述 链表(linked list)是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接(参考 <算法:C语言实现>). 根据结构的不同,链表可以 ...

  7. python基础下的数据结构与算法之链表

    一.链表的定义 用链接关系显式表示元素之间顺序关系的线性表称为链接表或链表. 二.单链表的python实现 class Node(object): """定义节点&quo ...

  8. Python实现的数据结构与算法之链表详解

    一.概述 链表(linked list)是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接.根据结构的不同,链表可以分为单向链表.单向循环链表.双向链表.双向循 ...

  9. Java数据结构和算法之链表

    三.链表 链结点 在链表中,每个数据项都被包含在‘点“中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LINK对象中 ...

随机推荐

  1. 基因id转换

    DAVID网站提供了id转换的功能 1 选择上传gene list文件 2 选择上传ID的类型,我们ID-list.txt中的是Ensembl Gene ID,所以这里选ENSEMBL_GENE_ID ...

  2. PHP与Cookie

    不管什么语言写的cookie,本质上没区别. cookie 常用于识别用户.cookie 是服务器留在用户计算机中的小文件.每当相同的计算机通过浏览器请求页面时,它同时会发送 cookie.通过 PH ...

  3. linux服务器安装tomcat

    linux服务器安装tomcat 准备: 下载一个tomcat,官网连接:http://tomcat.apache.org/ 版本选择合适的 安装tomcat之前要先安装Java jdk 可以参考我的 ...

  4. 【工具】导入导出 Excel

    文章目录 前言 当前支持的功能 方法api 配置 如何使用(Demo) 实现思路(该工具类可正确的一个大前提) 后记 前言 之前写的项目中,有个需求,需要导出导入Excel表格: 本来很简单的一件事, ...

  5. HCIA SWITCHING&ROUTTING 笔记——第一章 TCP/IP基础知识(2)

    视频地址:https://ilearningx.huawei.com/courses/course-v1:HuaweiX+EBGTC00000336+Self-paced/courseware/abb ...

  6. Istio技术与实践6:Istio如何为服务提供安全防护能力

    凡是产生连接关系,就必定带来安全问题,人类社会如此,服务网格世界,亦是如此. 今天,我们就来谈谈Istio第二主打功能---保护服务. 那么,便引出3个问题: l  Istio凭什么保护服务? l  ...

  7. Excel VBA 入门基础

    Private Sub RegExp_Replace() Dim RegExp As Object Dim SearchRange As Range, Cell As Range '此处定义正则表达式 ...

  8. 如何将SolidWorks文件另存为.obj文件及如何打开.obj格式文件

    原网站:http://fans.solidworks.com.cn/forum.php?mod=viewthread&tid=40238) OBJ文件是Alias Wavefront公司为它的 ...

  9. 在我的电脑中删除wps云文档图标

    在我的电脑中删除wps云文档图标 右键点击win10左下角选择运行,输入regedit打开注册表后,找到以下注册表路径: HKEY_CURRENT_USER\Software\Microsoft\Wi ...

  10. VBA数组(十四)

    我们都知道,一个变量是一个存储值的容器. 有时,开发人员希望一次可以在一个变量中保存多个值. 当一系列值存储在单个变量中时,则称为数组变量. 数组声明 数组声明的方式与声明变量相同,只是数组变量的声明 ...