基础数据结构:顺序表、链表——Python实现
来源:互联网 发布:我的世界冒险传说js 编辑:程序博客网 时间:2024/05/16 08:05
基础数据结构:顺序表、链表(单链表、双向循环链表)——Python实现
数据结构是我们实现算法的基础,在学习算法前我们先简单回顾一下数据结构的基础知识,具体内容网上都有博文详述,在此不过多赘述。
数据结构分为逻辑结构和存储(物理)结构:
逻辑结构:
-集合(set)
-线性结构(linearity)
-树形结构(tree)
-图形结构 (graph)存储结构:
-顺序(array)
-链式(linked list)
-索引(index)
-散列(hash)
在最初学习数据结构时,相信大家一定都是从线性表开始的,因为它是最简单、最基本、最常用的一种线性结构,根据存储方法可分为顺序表和链表,基本操作包括插入、删除和检索等。
为什么有这样的划分呢?我认为根本上是因为计算机存储的物理特性。
顺序存储结构把逻辑上相邻的结点存储在物理位置相邻的存储单元里,借助程序设计语言中的数组来实现。
链式存储结构则不要求逻辑相邻的结点物理位置也相邻,而是由附加的指针字段表示(存储相邻结点的地址),借助指针(c\c++)或引用(Java\Python)来实现。
以上两种存储结构,在不同情境下各有优劣:
– 从内存开销(空间复杂度)上来看,链表需要多附加指针字段(存放地址),因此对于64位寻址能力的系统来说,每个结点每增加一个指针(单链表)或是一个引用,都需要额外8个字节的内存。
– 从运算速度(时间复杂度)上来看,链表做插入和删除操作时效率更高,直接更改结点中指针指向的地址即可(时间复杂度O(1)),而顺序表则有可能需要移动整个数组(时间复杂度O(n))。但是在检索时,顺序表可以根据索引号n直接访问到对应元素(时间复杂度O(1)),而链表则需要从头结点开始依次访问到目标元素(时间复杂度O(n))。当n非常大时,这对程序运行效率的影响是十分巨大的。
– 另外,对于像c\c++\java这样的程序设计语言,由于数组的创建时需要给定大小,因此顺序表是相对固定的;而链表则可以在有元素插入时生成一个结点并与链表连接,是一个相对动态的过程。但其实我们也可以动态的改变顺序表的大小,根据表中元素的个数扩增或缩减数组的大小,这就是所谓的调整数组(resizing array)。Python中的数据结构列表list,就是采用这种思想来设计的动态顺序表,有兴趣的可以参考这篇博客:Python中list的实现,英文原文:Python list implementation。
由于计算机硬件基础的发展,我们对于链表几个几十个字节的额外内存开销,在可以提升运算效率的前提下,一般是可以接受的。但是对于数据表的基本操作,我们如何对其运算效率做到综合最优,这就是算法所需要研究的问题了。
以下是Python 3的实现:
# 顺序表class List: def __init__(self): self.list = [] def __str__(self): return str(self.list) def put(self, item): self.list.append(item) def size(self): return len(self.list) def isEmpty(self): return self.list == []
# 单链表class LinkedList: # 定义结点内部类 class __Node: item = None next = None def __init__(self, item, n): self.item = item self.next = n def __init__(self): self.__head = self.__Node(None,None) self.__size = 0 def __str__(self): p=self.__head.next l=[] while p: l.append(p.item) p = p.next return str(l) # 头插法 def put(self, item): node = self.__Node(item, self.__head.next) self.__head.next = node self.__size += 1 # 删除第一个结点 def remove(self): node = self.__head.next self.__head.next = node.next self.__size -= 1 del node def size(self): return self.__size def isEmpty(self): return self.__size == 0
# 测试list=List()for i in range(0,10): list.put(i)print(list.size())print(list)# 输出>>10>>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 测试ll=LinkedList()for i in range(0,10): ll.put(i)print(ll.size(),ll)ll.remove()print(ll.size(),ll)# 输出>>10 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]>>9 [8, 7, 6, 5, 4, 3, 2, 1, 0]
这里对单链表的put()方法使用了头插法,如果想要插在最后则需要将所有结点都访问一般,当链表结点个数非常多时,这无疑非常耗时,因此我们可以增加rear字段来指向最后一个结点。但是在删除尾部结点时,我们需要将rear移动到其前一个结点,为了能直接访问到前一个结点,我们可以增加last字段指向前一个结点。
这就是所谓的双向链表,是我们牺牲一点点内存来加速访问速度的产物。
接下来如果我们将head与最后一个结点连接,就构成了双向循环链表,这时候其实可以不再需要rear字段,因为head.last指向的就是尾结点。
# 双向循环链表class DoubleLoopLinked: class __Node: item = None next = None last = None def __init__(self, item, n, l): self.item = item self.next = n self.last = l def __init__(self): self.__head = self.__Node(None, None, None) self.__size = 0 def __str__(self): p = self.__head.next l = [] while p != self.__head: l.append(p.item) p = p.next return str(l) # 尾插法 def insertToTail(self, item): if self.isEmpty(): node = self.__Node(item, self.__head, self.__head) self.__head.next = node self.__head.last = node else: node = self.__Node(item, self.__head, self.__head.last) self.__head.last.next = node self.__head.last = node self.__size += 1 # 头插法 def insertToHead(self, item): if self.isEmpty(): node = self.__Node(item, self.__head, self.__head) self.__head.next = node self.__head.last = node else: node = self.__Node(item, self.__head.next, self.__head) self.__head.next.last = node self.__head.next = node self.__size += 1 # 删除 def removeHead(self): node = self.__head.next self.__head.next = node.next node.next.last = self.__head self.__size -= 1 del node def removeTail(self): node = self.__head.last self.__head.last = node.last node.last.next = self.__head self.__size -= 1 del node def size(self): return self.__size def isEmpty(self): return self.__size == 0
dll = DoubleLoopLinked()dll.insertToHead(1)dll.insertToHead(2)dll.insertToHead(3)dll.insertToTail(4)dll.insertToTail(5)print(dll.size(),dll)dll.removeHead()dll.removeTail()print(dll.size(),dll)>>5 [3, 2, 1, 4, 5]>>3 [2, 1, 4]
- 基础数据结构:顺序表、链表——Python实现
- 基础数据结构——顺序线性表
- 【python】python数据结构(一)——线性表:顺序表的实现
- 数据结构--顺序表定义及python实现
- 数据结构的实现——顺序表
- 数据结构——Java实现顺序表
- 数据结构—顺序表的实现
- 数据结构—动态顺序表的实现
- 数据结构—顺序表的实现
- 【数据结构基础】顺序表
- 数据结构—顺序表
- 数据结构学习之线性表的顺序实现(python 实现)
- Java基础数据结构——链表与顺序表
- hrbust1545 基础数据结构——顺序表(2)
- 基础数据结构:栈、队列——Python实现
- 数据结构顺序表实现
- 一、数据结构基础之顺序表C语言实现
- 数据结构基础【07】队列的顺序实现
- JEECG 3.7.1版本发布,企业级JAVA快速开发平台
- matlab批量读取文件的方法
- 清除浮动的方法
- 多线程编程(一)——写一个简单的死锁
- 9月13日云栖精选夜读:除了清空购物车,阿里年会的技术也超霸气!
- 基础数据结构:顺序表、链表——Python实现
- Micro Python微控制器
- 存储器、硬盘 内存 缓存 寄存器
- Java的动态绑定和静态绑定
- gets 和 scanf 的区别
- 多么痛的领悟---关于RMB数据类型导致的元转分分转元的bug
- 124_binaryTreeMaximumPathSum
- iOS WebView 图片点击放大并左右滑动,类似微信/网易文章功能
- bootstrap-datetimepicker时间控件