【数据结构与算法】之线性表的应用和操作
数据结构概念
- 数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。
- 数据结构的逻辑结构:数据对象中数据元素之间的相互关系,分为线性结构、树形结构、图形结构以及集合结构。
- 数据结构的物理结构:数据的逻辑结构在计算机中的存储形式,分为顺序存储和链式存储(不连续存储)。
- 算法:解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
- 算法五个基本特性:输入、输出、有穷性、确定性和可行性。
- 算法时间复杂度O(n):常数阶、线性阶、平方阶、对数阶、立方阶、nlogn阶、指数阶。
- 耗时排序:O(1) < O(logn) < O(n) < O(nlgn) < O(x2) < O(x3) < O(2n) < O(n!) < O(nn)。
线性表
一、概念
- 线性表:就是零个或者多个数据元素的有限序列,数据元素之间是一对一的关系;
- 性质:数据元素可以为空;数据元素有限;数据元素之间的逻辑结构为线性结构,也就是一对一的关系;数据元素类型相同。
线性表的抽象数据类型:
ADT 线性表(List)
Data线性表的数据对象集合为{a1, a2, ......, an},每一个元素的类型都是DataType。其中,除第一个元素a1外,每一个元素有且仅有一个直接前驱元素,除了最后一个元素an外,每一个元素有且仅有一个直接后续元素。数据元素之间的关系是一对一的关系。
Operationcount:线性表元素个数。first:头指针。last:尾指针。isEmpty():若线性表为空,返回true,否则返回false。remove():将线性表清空node(i):将线性表中的第i个位置的元素返回。insert(data,i):在线性表中的第i个位置插入新数据data。
EndADT
二、顺序线性表
- 顺序线性表:使用一段连续的地址存储单元放置线性表的数据元素。
- 顺序存储的插入步骤:
① 线性表长度大于等于数组长度,抛出异常;
② 插入位置不合适,抛出异常(判断插入位置与0和最大值的大小);
③ 从最后一个元素开始向前变量,将它们都向后移动一位;
④ 将要插入的元素填入指定位置;
⑤ 表长加一; - 顺序存储的删除步骤:
① 线性表是否为空;
② 删除位置不合适,抛出异常(判断插入位置与0和最大值的大小);
③ 取出删除元素;
④ 从删除元素的位置遍历到最后一个元素位置,将它们前移一位;
⑤ 表长减一; - 顺序线性表的优缺点:
优点 | 缺点 |
---|---|
可以快速获取下标的数据元素,时间复杂度为O(1) | 插入和删除操作需要移动大量的元素,时间复杂度为O(n) |
逻辑关系是一对一的关系,连续存储单元足以储存,不需要增加额外的存储空间 | 线性表的存储空间大小难以确定,并且不好扩展 |
造成存储空间碎片 |
三、链式线性表
- 链式线性表:线性表的数据元素可以存储在随意的存储单元,每一个节点不仅仅包括数据元素还有一个指向下一个节点的指针(基本的单链表)。
- 链式(单链表)和顺序线性表优缺点对比:
链式线性表 | 顺序线性表 | |
---|---|---|
存储方式 | 任意地址存储空间 | 一段地址连续的存储空间 |
时间性能(查找) | O(n) | O(1) |
时间性能(插入和删除) | 寻找相应的节点,时间复杂度为O(n),然后,插入和删除为O(1) | O(n) |
空间性能 | 不需要提前分配空间,只要有存储空间分配就行,数据元素个数只受可分配存储空间大小的限制 | 需要提前分配存储空间,分配大了,浪费空间,分配小了,容易发生上溢 |
- 链式线性表的基本分类:
名称 | 描述 |
---|---|
单向链表 | 一段地址连续的存储空间 |
静态链表 | 使用顺序结构实现链式线性表 |
双向链表 | 每个节点除了数据元素,还包含一个指向上一个节点的指针和一个指向下一个节点的指针 |
循环链表 | 线性表的尾部指向头节点,形成一个闭环 |
四、双向链表
- 节点定义:
public class LinkedListNode<T> {var data: T //Data could not be nil.var previous: LinkedListNode? //The pointer to previous node.var next: LinkedListNode? //The pointer to next node.init(_ data: T) {self.data = data}
}
- 双向链表:head指向第一个有数据的节点,有的线性表会生成一个头节点,该节点不存储任何数据或者只存储该链表的长度,该节点指向第一个有数据的节点。这样做的好处就是,第一个节点的删除和插入操作和其他节点保持一致。
public enum ErrorStatus {case Error(message: String)case OK
}public class DoubleLinkedList<T> {public typealias Node = LinkedListNode<T>private var head: Node? //Head node of link list.public var isEmpty: Bool { //If link list has no data, return true.return head == nil}public var first: Node? { //Get first node is the head of link list.return head}public var last: Node? { //Last node of link list....return node}public var count: Int { //Retrun link list's nodes count....return count}public func node(atIndex index: Int) -> Node? { //Get node with index...return node}public func appendData(data: T) { //Append data to link list tail...}public func insert(data: T, atIndex index: Int) -> ErrorStatus { //Insert data at indexguard index >= 0, index <= count else {return ErrorStatus.Error(message: "Index is out of range!")}let newNode = Node(data)if index == 0 {if let node = first {head = newNodenewNode.next = nodenode.previous = newNode} else {head = newNode}} else {let node = self.node(atIndex: index-1)let nextNode = self.node(atIndex: index)node?.next = newNodenewNode.previous = nodenewNode.next = nextNodenextNode?.previous = newNode}return ErrorStatus.OK}public func remove(atIndex index: Int) -> (T?, ErrorStatus) { //Remove node at indexguard !isEmpty else {return (nil, ErrorStatus.Error(message: "Link list is Empty!"))}guard index >= 0, index < count else {return (nil, ErrorStatus.Error(message: "Index is out of range!"))}let node = self.node(atIndex: index)let nextNode = self.node(atIndex: index+1)if index == 0 {head = nextNode} else {let beforeNode = self.node(atIndex: index-1)beforeNode?.next = nextNodenextNode?.previous = beforeNode}return (node?.data, ErrorStatus.OK)}
}
- insert操作:无论insert还是remove都是先拆链,然后再组合成新的数据链。
① 先判断需要插入数据的index是否在[0, count]的范围之内,注意这里是方括号,也就是包含边界,因为线性表最前面和最后面都可以插入新的数据;
② 生成新节点;
③ 因为这里的双向链表没有采取头节点的方式实现,所以,插入第一个节点和其他节点有点不一样,需要做一些判断;
④ 如果是插入第一个节点,则判断如果该链表为空,则直接设置head=newNode;如果该链表不为空,则将一个节点赋值给node,然后将newNode赋值给head,接着将node赋值给newNode.next,最后设置node.previous=newNode;
⑤ 如果不是插入一个节点,则先获取下标为index-1的节点node,然后获取下标为index的节点nextNode。设置node.next=newNode,然后newNode.next=nextNode,连成一条指向下一个数据元素的链,最后设置newNode.previous=node和nextNode.previous=newNode连上指向上一个数据元素的链,自此,先的数据插入成功;
public func insert(data: T, atIndex index: Int) -> ErrorStatus { //Insert data at indexguard index >= 0, index <= count else {return ErrorStatus.Error(message: "Index is out of range!")}let newNode = Node(data)if index == 0 {if let node = first {head = newNodenewNode.next = nodenode.previous = newNode} else {head = newNode}} else {let node = self.node(atIndex: index-1)let nextNode = self.node(atIndex: index)node?.next = newNodenewNode.next = nextNodenewNode.previous = nodenextNode?.previous = newNode}return ErrorStatus.OK
}
- remove操作:
① 先判断是否是空链,如果是则返回,否则再判断需要删除数据的小表是否在合理范围内,如果不是则返回;
② 判断index是否等于0,如果是,则直接将head=secondNode;
③ 获取beforeNode和nextNode,然后将beforeNode.next=nextNode,nextNode,previous=beforeNode,自此,下标为index的节点,没有任何对象指向它,在当前函数域外就外被系统回收掉;
public func remove(atIndex index: Int) -> (T?, ErrorStatus) { //Remove node at indexguard !isEmpty else {return (nil, ErrorStatus.Error(message: "Link list is Empty!"))}guard index >= 0, index < count else {return (nil, ErrorStatus.Error(message: "Index is out of range!"))}let node = self.node(atIndex: index)let nextNode = self.node(atIndex: index+1)if index == 0 {head = nextNode} else {let beforeNode = self.node(atIndex: index-1)beforeNode?.next = nextNodenextNode?.previous = beforeNode}return (node?.data, ErrorStatus.OK)
}
五、总结
- 若线性表需要频繁查找,很少进行插入和删除操作时,使用顺序存储结构;反之,使用链式存储结构。
- 如果提前知道线性表需要的存储空间,可以使用顺序结构;如果不知道线性表中的数据元素变化有多大,即不确定需要多大的存储空间,则使用链式存储结构。
【数据结构与算法】之线性表的应用和操作相关推荐
- 从零开始学数据结构和算法(二)线性表的链式存储结构
链表 链式存储结构 定义 线性表的链式存储结构的特点是用一组任意的存储单元的存储线性表的数据元素,这组存储单元是可以连续的,也可以是不连续的. 种类 结构图 单链表 应用:MessageQueue 插 ...
- 黑马程序员 C语言数据结构与算法之线性表(链表/栈/队列/顺序表)
C语言 链表基础知识清晰讲解(黑马) 讲的蛮好,就是音质不太好,有时听不清讲的啥! [黑马]数据结构与算法之线性表(链表/栈/队列/顺序表)[配套源码 嘛蛋,看错了,这是java的... 文章目录 链 ...
- rsa算法c语言实现_数据结构与算法之线性表-顺序表实现(C语言版本)
原文托管在Github: https://github.com/shellhub/blog/issues/52 数据结构与算法之线性表-顺序表实现(C语言版本) 前言 数据结构与算法是一个程序员必备的 ...
- 数据结构与算法(一) 线性表之顺序表
线性表是一种最简单.最常用的数据结构,根据存储方式可以分为顺序表和链表. 顺序表: 顺序表指的是用一组地址连续的存储单元依次存储线性表的数据元素,称为线性表的顺序存储结构或顺序映像(sequent ...
- 数据结构和算法基础--线性表
数据结构和算法基础–线性表 数据结构 = 数据的逻辑结构+数据的存储结构+数据的运算 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28ek7MfI-164242629 ...
- 实验一 线性表的顺序存储与实现_程序员:数据结构与算法,线性表介绍
线性表 线性表(list):零个或多个数据元素的有限序列. 举个例子:一个班的小朋友,一个跟着一个排队,当中的每个小朋友都知道他前面的是谁,后面的是谁,如同一根线把他们串联起来.就可以称之为线性表. ...
- Java数据结构和算法:线性表
线性表的定义 线性表(linear-list)是最常用最简单的一种数据结构.一个线性表是n (n≥0)个相同类型数据元素的有限序列.记为: L= (a1, a2 , - , an ). 其中,L是表名 ...
- 学习笔记-数据结构与算法之线性表
目录 框架图 线性表 顺序结构 创建线性表 输出验证 获取第i个元素 插入元素到特定位置 删除特定位置元素 整体代码 链式结构 创建链表 输出验证 获取第i个元素 插入元素 删除元素 删除整表 完整代 ...
- 数据结构与算法之线性表(超详细顺序表、链表)
原创公众号:bigsai 文章已收录在 全网都在关注的数据结构与算法学习仓库 欢迎star 前言 通过前面数据结构与算法基础知识我么知道了数据结构的一些概念和重要性,那么我们今天总结下线性表相关的内容 ...
- 《数据结构与算法》——线性表顺序存储结构的插入与删除
什么是线性表? 线性表是最基本.最简单.也是最常用的一种数据结构.线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列. 线性表中数据元素之间的关系是一对 ...
最新文章
- 域控服务器状态检查和标准备份
- eclipse部署的web项目没有添加到Tomcat的webapps目录下解决方法
- django 快速实现session的操作
- 6000字思考!一篇看懂促销系统的底层逻辑
- ABAP动态生成经典应用之Table数据Upload 程序
- 资深专家深度剖析Kubernetes API Server第2章(共3章)
- 扩展jquery scroll事件,支持 scroll start 和 scroll stop
- Python——二维数组遍历操作
- phpstorm 10 注册码
- android 下载网络图片并缓存
- JVM监控及诊断工具GUI篇之Eclipse MAT
- python无限循环怎么停止,如何在Python中安全地停止无限循环?
- Markdown编辑器-初始模板参考
- Webview--如何让加载进来的页面自适应手机屏幕分辨率
- mxnet load生成的json模型告警src/nnvm/legacy_json_util.cc:204: Warning: loading symbol saved by MXNet versio
- CLI 什么是 command-line interface
- 鸟哥的Linux私房菜(基础篇)- 第二十一章、系统配置工具(网络与打印机)与硬件侦测
- 我来补充两句京东和企业软件
- 生信技能树课程记录笔记(七)20220531
- Bootstrap2和3的区别与选择
热门文章
- Delphi 10.X 不用联接真机或模拟器编译出APK
- ffmpeg安装与配置
- Gradient Boost Decision Tree(GBDT)中损失函数为什么是对数形式
- ZOJ3865:Superbot(BFS) The 15th Zhejiang University Programming Contest
- UVa 11121 Base -2(负数进制)
- [Ray Linn]用Visual Studio 2008开发IE BHO (浏览器帮助对象)之一
- SQL 触发器的使用
- 10-27 插入学生总学分表 (10 分)
- C语言学习用迭代法求x=√a
- 作业一 郝树伟 1101210664