目   录

1. 链表

1.1 链表概念

1.2 链表优点

1.3 链表缺点

2.常见链表结构

2.1 单链表

2.1.1 单链表结构

2.1.2 单链表代码实现

2.2 单向循环链表

2.2.1 单向循环链表结构

2.2.2 单循环链表代码实现

2.3 双向链表

2.3.1 双向链表结构

2.3.2 双向链表代码实现


1. 链表

1.1 链表概念

前面提到,栈、队列都可以视作是一种特殊的线性表,在绝大多数语言中都是连续存储的。而链表则是不连续的存储方式,自适应内存大小,通过指针的使用,灵活将不同的内存块联系起来,实现动态增加动态删除。

链表的基础是结点 node,每个结点应该包含至少两个区域,一个是存放数据的区域,一个是指向下一个节点的指针。对于整个链表而言,应该有指向头结点的头指针,尾部结点根据链表的不同类型可以指向空(单链表),也可以指向头节点(循环链表)。根据指针的配置,结点可以是单向的,也可以是双向的,从而链表可以是单向的,也可以是双向的。

1.2 链表优点

相对于连续存储的结构, 链表优点还是很明显的:

  1. 内存空间是不连续的,可以充分利用计算机的零碎内存,实现灵活的内存动态管理。
  2. 链表不必在创建时就确定大小, 并且大小可以无限的延伸下去(如果计算机内存支持的话)。
  3. 链表在插入和删除数据时, 只需要移动少量数据,时间复杂度会降低很多。

1.3 链表缺点

链表也有一些缺点:

  1. 链表如果按照位置访问,访问任何一个位置的元素时, 都需要从头开始访问(无法跳过第一个元素访问任何一个元素)。即无法通过下标直接访问元素。备注:笔者认为,没有完美的数据结构能够满足所有用户需求,无论是栈、队列抑或是链表,都需要结合实际数据特性和用户使用特性来决定数据结构。比如链表的这个缺点,如果数据不需要按照位置访问,可能就不是缺点。
  2. 因为需要存储指向下一个结点的指针,额外要消耗内存。

2.常见链表结构

2.1 单链表

2.1.1 单链表结构

单链表是最简单的链式存取的数据结构,每个单独数据是以对应的结点来表示的,每个结点由元素和指针构成。

2.1.2 单链表代码实现

单向链表需要实现的基本操作有:

  1. 创建链表
  2. 新增结点到链表尾部
  3. 删除第n个结点
  4. 读取第n个结点
  5. 逆转顺序读取链表(非必需)

      每个人有每个人的设计代码实现,有些同学在单链表中只设计一个头指针,需要在链表尾部新增数据时候从头指针一直查找到最后,而我喜欢创建头指针、尾指针两个指针,以空间换时间,代码实现也更简单。

下面是我的代码实现:

class Node():def __init__(self,value):self.val=valueself.next=Noneclass SingleLink():def __init__(self):self.phead=Noneself.ptail=Noneself.length=0def add(self,value):node=Node(value)if(not self.phead):self.phead=nodeself.ptail=nodeself.length=1else:self.ptail.next=nodeself.ptail=nodeself.ptail.next=Noneself.length+=1#删除第 n 个结点def delete(self,n):#如果当前链表为空,不操作if(self.length==0):return(None)# 如果超出现有长度,删除最后一个结点if(n>self.length):n=self.length# 如果删除第一个结点,即头节点# 则直接移动头指针到下一个结点if(n==1):self.phead=self.phead.nextself.length-=1return(None)# 获得头指针p=self.phead# 目的是获得被删除结点的前一个结点while(n>2):p=p.nextn-=1# 如果这是最后一个结点,那么前一个结点直接指向空# 如果这不是最后一个结点,那么前一个结点直接指向再下一个结点if(p.next.next):p.next=p.next.nextelse:p.next=Noneself.length-=1def read(self,n):if(n>self.length):n=self.lengthp=self.pheadwhile(n>1):p=p.nextn-=1return(p.val)def show(self):print("current length is {0}".format(self.length))p=self.pheadwhile( p.next ):print(p.val,end=" , ")p=p.nextprint(p.val)return(None)def reverse_show(self,node):p=nodeif(p.next):self.reverse_show(p.next)print(p.val,end=" , ")

运行相关测试代码后结果如下:

#创建单链表
a_link=SingleLink()#填充数据 1~9
for i in range(1,10):a_link.add(i)
print()#展示数据
print("*"*30+"填充数据 1~9之后链表为"+"*"*30)
a_link.show()#逆序展示数据
print("*"*30+"逆序展示链表数据"+"*"*30)
a_link.reverse_show(a_link.phead)
print()#连续两次删除头节点
print("*"*50)
print("Now to delete first node twice")
a_link.delete(1)
a_link.show()
a_link.delete(1)
a_link.show()
print("*"*50)#连续两次删除尾节点
print("Now to delete last node twice")
a_link.delete(7)
a_link.show()
a_link.delete(6)
a_link.show()
print("*"*50)#删除中间结点第二个结点
print("Now to delete second node ")
a_link.delete(2)
a_link.show()
print("*"*50)

2.2 单向循环链表

2.2.1 单向循环链表结构

单向循环链表即将单链表的尾结点指向头结点的链表,又称之为循环单链表(Circular linkedlist)。

2.2.2 单循环链表代码实现

单循环链表需要实现的基本操作有:

  1. 创建链表
  2. 新增结点到链表尾部
  3. 新增结点到链表第 n 个结点
  4. 删除第n个结点
  5. 读取第n个结点

同样,在单循环链表中,如果设计头指针、尾指针两个指针,则不光是空间换时间,而且代码实现会更方便。

下面是我的代码实现:

class Node():def __init__(self,value):self.val=valueself.next=Noneclass S_CirLink():def __init__(self):self.phead=Noneself.ptail=Noneself.length=0def addTail(self,value):node=Node(value)if(not self.phead):self.phead=nodeself.ptail=nodenode.next=nodeself.length=1else:self.ptail.next=nodeself.ptail=nodenode.next=self.pheadself.length+=1# n 限制在大于等于 1 def addN(self,value,n):node=Node(value)if(not self.phead):self.phead=nodeself.ptail=nodenode.next=nodeself.length=1else:if(n==1):node.next=self.pheadself.phead=nodeself.ptail.next=self.pheadself.length+=1return(None)if(n>self.length):n=self.length+1p=self.pheadwhile(n>2):p=p.nextn-=1node.next=p.nextp.next=nodeself.length+=1return(None)#删除第 n 个结点def delete(self,n):#如果当前链表为空,不操作if(self.length==0):return(None)# 如果超出现有长度,删除最后一个结点if(n>self.length):n=self.length# 如果删除第一个结点,即头节点# 则直接移动头指针到下一个结点if(n==1):if(self.length==1):self.phead=Noneself.ptail=Noneself.length=0return(None)self.phead=self.phead.nextself.ptail.next=self.pheadself.length-=1return(None)# 此处处理链表长度大于1 的情况,获得头指针p=self.phead# 目的是获得被删除结点的前一个结点while(n>2):p=p.nextn-=1# 因为是循环链表,所以链表长度大于1时候删除一个结点,# 链表肯定不为空,直接指向下一个链表即可if(p.next!=self.ptail):p.next=p.next.nextelse:p.next=p.next.nextself.ptail=pself.length-=1def read(self,n):if(n>self.length):n=self.lengthp=self.pheadwhile(n>1):p=p.nextn-=1return(p.val)def show(self):print("current length is {0}".format(self.length))p=self.pheadwhile( p.next!=self.phead ):print(p.val,end=" , ")p=p.nextprint(p.val)return(None)

测试代码如下:

#创建单向循环链表
a_link=S_CirLink()#填充数据 1~9
for i in range(1,10):a_link.addTail(i)
print()#展示数据
print("*"*30+"填充数据 1~9之后链表为"+"*"*30)
a_link.show()#连续两次删除头节点
print("*"*50)
print("Now to delete first node twice")
a_link.delete(1)
a_link.show()
a_link.delete(1)
a_link.show()
print("*"*50)#删除中间结点第二个结点
print("Now to delete second node ")
a_link.delete(2)
a_link.show()
print("*"*50)#连续两次删除尾节点
print("Now to delete last node twice")
a_link.delete(7)
a_link.show()
a_link.delete(6)
a_link.show()
print("*"*50)# 增加一个结点,排序为 3
print("Now to add new  node in third place,the value is 11")
a_link.addN(11,3)
a_link.show()# 增加一个尾结点,排序为 6
print("Now to add new  node in 6th place,the value is 12")
a_link.addN(12,6)
a_link.show()

运行结果:

2.3 双向链表

2.3.1 双向链表结构

双向链表是结点 Node 既有一个 prev (前驱指针) ,又有一个 next (后驱指针) 来构成的一种数据结构。

2.3.2 双向链表代码实现

双向链表需要实现的基本操作有:

  1. 创建双向链表
  2. 新增结点到链表尾部
  3. 新增结点到链表第 n 个结点
  4. 删除第n个结点
  5. 读取第n个结点

下面是我的代码实现:

class Node():def __init__(self,value):self.val=valueself.prev=Noneself.next=Noneclass Bid_Link():def __init__(self):self.phead=Noneself.ptail=Noneself.length=0def addTail(self,value):node=Node(value)if(not self.phead):self.phead=nodeself.ptail=nodeself.length=1else:self.ptail.next=nodenode.prev=self.ptailself.ptail=nodenode.next=Noneself.length+=1def addN(self,value,n):if(not self.phead or n>self.length):self.addTail(value)return(None)node=Node(value)if(n==1):node.next=self.pheadself.phead.prev=nodeself.phead=nodeself.length+=1return(None)p=self.pheadwhile(n>2):p=p.nextn-=1node.prev=pnode.next=p.nextnode.next.prev=nodep.next=nodeself.length+=1return(None)#删除第 n 个结点,n 大于等于 0def delete(self,n):#如果当前链表为空,不操作if(self.length==0):return(None)# 如果超出现有长度,删除最后一个结点if(n>self.length):n=self.length# 如果删除第一个结点,即头节点# 则直接移动头指针到下一个结点if(n==1):if(self.length==1):self.phead=Noneself.ptail=Noneself.length=0return(None)self.phead=self.phead.nextself.phead.prev=Noneself.length-=1return(None)# 此处处理链表长度大于1 的情况,获得头指针p=self.phead# 目的是获得被删除结点的前一个结点while(n>2):p=p.nextn-=1# 双向链表,需要处理前驱指针、后驱指针tmp=p.nextif(p.next.next):p.next=tmp.nexttmp.next.prev=pelse:p.next=Noneself.ptail=pself.length-=1return(None)def read(self,n):if(n>self.length):n=self.lengthp=self.pheadwhile(n>1):p=p.nextn-=1return(p.val)def show(self):print("current length is {0}".format(self.length))p=self.pheadwhile(p.next):print(p.val,end=" , ")p=p.nextprint(p.val)return(None)

测试代码如下:

#创建双向循环链表
a_link=Bid_Link()#填充数据 1~9
for i in range(1,10):a_link.addTail(i)
print()#展示数据
print("*"*30+"填充数据 1~9之后链表为"+"*"*30)
a_link.show()#连续两次删除头节点
print("*"*50)
print("Now to delete first node twice")
a_link.delete(1)
a_link.show()
a_link.delete(1)
a_link.show()
print("*"*50)#删除中间结点第二个结点
print("Now to delete second node ")
a_link.delete(2)
a_link.show()
print("*"*50)#连续两次删除尾节点
print("Now to delete last node twice")
a_link.delete(7)
a_link.show()
a_link.delete(6)
a_link.show()
print("*"*50)# 增加一个结点,排序为 3
print("Now to add new  node in third place,the value is 11")
a_link.addN(11,3)
a_link.show()# 增加一个尾结点,排序为 6
print("Now to add new  node in 6th place,the value is 12")
a_link.addN(12,6)
a_link.show()

运行结果:

数据结构 09-链表概念及常见链表结构相关推荐

  1. 【数据结构】数据结构的基本概念——逻辑结构、存储结构、抽象数据类型

    文章目录 一.基本概念和术语? 1.数据 2.数据元素 3.数据项(属性.字段) 4.数据对象 5.数据结构 二.逻辑结构和物理结构(存储结构) 1.逻辑结构 1)定义 2)分类(线性结构和非线性结构 ...

  2. 数据结构 - 链表 - 面试中常见的链表算法题

    数据结构 - 链表 - 面试中常见的链表算法题 数据结构是面试中必定考查的知识点,面试者需要掌握几种经典的数据结构:线性表(数组.链表).栈与队列.树(二叉树.二叉查找树.平衡二叉树.红黑树).图. ...

  3. 链表list(链式存储结构实现)_数据结构知否知否系列之 — 线性表的顺序与链式存储篇(8000 多字长文)...

    从不浪费时间的人,没有工夫抱怨时间不够. -- 杰弗逊 线性表是由 n 个数据元素组成的有限序列,也是最基本.最简单.最常用的一种数据结构. 作者简介:五月君,Nodejs Developer,热爱技 ...

  4. 数据结构——常见链表算法题

    数据结构--常见链表算法题(C++运行) 本文介绍常见的有关链表的算法题,值得一提的是,该代码无需在力扣上,可在本地运行成功. 题目八道: 1.反转链表 2.移除链表中的重复节点 3.查找链表中的中间 ...

  5. SDUT_2121数据结构实验之链表六:有序链表的建立 (对建立的单项链表结构进行排序)

    点击打开链接 数据结构实验之链表六:有序链表的建立 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem ...

  6. java链式结构_(Java)单链表Java语言链式结构实现(数据结构四)

    1.迭代器接口实现 package com.zhaochao; public interface Iterator { boolean hasNext(); E next(); boolean del ...

  7. php数据结构链表代码,数据结构之线性表——链式存储结构之单链表(php代码实现)...

    /** * * 1. 类LNode用作创建单链表时,生成新的节点. * 2. 类SingleLinkList用于创建单链表以及对单链表的一些操作方法(实例化此类就相当于创建了一个空链表) * 3. C ...

  8. 数据结构之线性表——链式存储结构之单链表(php代码实现)

    <?php /**** 1. 类LNode用作创建单链表时,生成新的节点.* 2. 类SingleLinkList用于创建单链表以及对单链表的一些操作方法(实例化此类就相当于创建了一个空链表)* ...

  9. 数据结构 | 如何一文搞定链表问题?(附20本书获奖名单)

    这是本公号的第127篇原创. 近期看到一个数据结构题目,翻转链表.动手写了下代码,手生了不少,发现好铁不用也会生锈,大脑也如此. 于是就整体回顾了一下链表的常见操作和数据结构题,整理下分享出来,万一对 ...

  10. 408考研数据结构与算法之数组、链表、队列、栈知识点和算法详细教程(更新中)

    第一章:数据结构与算法概述 因为数据结构作为计算机专业的专业基础课程,是计算机考研的必考科目之一,如果打算报考计算机专业的研究生,你必须学好它. 数据结构是计算机软考.计算机等级考试等相关考试的必考内 ...

最新文章

  1. Connection reset by peer原理解析
  2. 数组中子数组运算常见写法
  3. Linux新手生存笔记[2]——vim训练稿
  4. MySQL 中 MyISAM 中的查询为什么比 InnoDB 快?
  5. 直观展示卷积核(转)
  6. window docker mysql_windows使用docker运行mysql等工具(二)安装运行mysql
  7. HBase Java API 创建表时一直卡住
  8. [python调试笔记] 编译运行h5py
  9. Codeforces 919D - Substring
  10. Android开发:5-2、ListView、GridView、Spinner
  11. PHP数组合并+与array_merge的区别分析 对多个数组合并去重技巧
  12. matlab将图片旋转的代码_【MATLAB】钟表
  13. 面试必会之LinkedList源码分析
  14. Java基础学习总结(73)——Java最新面试题汇总
  15. Redis 通配符查找及批量删除key
  16. c语言所有逻辑符号大全,C语言中的逻辑取反是“~”符号吗逻辑或是“|”符号吗?...
  17. 频繁gc是什么意思_CPU飙高,频繁GC,怎么排查?
  18. BTA12A-ASEMI的IGBT管BTA12A
  19. 新Word文档借用旧文档的部分样式
  20. oracle SQL先按字母排序再按数字排序

热门文章

  1. 5000预算组装台式机配置清单
  2. 【有利可图网】PS教程:制作变形文字
  3. c语言程序提速,用C语言加速程序进而加速硬件速度
  4. Java web 购物网站开发
  5. win10系统计算机如何分盘,win10怎么进行分盘_win10电脑如何合理分盘
  6. win10计算机分盘怎么设置密码,Win10如何限制磁盘分区被访问 Win10自带磁盘加密功能BitLocker在哪里...
  7. 电信天翼网关与路由器级联
  8. ssm框架整合以及登录案例
  9. win10蓝屏代码_如何让电脑蓝屏 让电脑蓝屏方法介绍【详解】
  10. 计算机在档案管理中的作用,计算机在档案管理中的运用