什么是链表

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

(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. LeetCode 108. 将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree) 14

    108. 将有序数组转换为二叉搜索树 108. Convert Sorted Array to Binary Search Tree 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索 ...

  2. 随记sqlserver学习笔记

    create database libraryDBgouse libraryDBgo--读者信息表create table ReaderInfo( ReaderId int not null prim ...

  3. Eclipse设置每行的最大字符数

    Eclipse默认宽度是 120 个字符.如下图所示(提示:格式化快捷键Ctrl + Shift + F): 设置步骤如下: 菜单栏倒数第二项,选择Window 下拉栏最后一项,选择Preferenc ...

  4. 记录一次kafka解决相同userId顺序消费的问题

    基本思路:在kafka生产者生产消息时,把相同userId的消息落在同一个分区/partition public void sendTopic1(String tpoic, String userId ...

  5. SVN_06导入项目文档

    把这个项目的文档迁入到SVN Server上的库中 [1]首先右键点击projectAdmin目录,这时候的右键菜单例如以下图看到的:选择copy URL toCLipboard,就是复制统一资源定位 ...

  6. C# SpinLock用法。

    class Program { static void Main(string[] args) { ; ]; Stopwatch sp = new Stopwatch(); sp.Start(); / ...

  7. ubuntu环境下pycharm编译程序import包出错:ImportError: dynamic module does not define init function (init_caffe)

    出错原因是因为pycharm中的python版本不对,比如程序为2.7版本,但是pycharm编解释器为python3,导致出错,去setting改一下版本就行:pycharm>file> ...

  8. maven - 多模块构建

    使用idea创建maven项目 点击next输入GroupId和ArtifactId 点击next创建项目,新建项目结构如下 修改demo打包方式为pom 按层级拆分创建模块model,server, ...

  9. ReactNative报错null is not an object (evaluating '_rngesturehandlermodule.default.direction')

    程序报错: null is not an object (evaluating 'rngesturehandlermodule.default.direction') 解决: react-native ...

  10. 基于socket.io客户端与服务端的相互通讯

    socket.io是对websocket的封装,用于客户端与服务端的相互通讯.官网:https://socket.io/. 下面是socket.io的用法: 1.由于使用express开的本地服务,先 ...