大话数据结构学习笔记-第三章线性表
目录:
- 一.大话数据结构电子图书下载地址
- 二.线性表
- 三.顺序存储结构
- 1.什么是顺序存储结构?
- 2.顺序存储结构索引表常用操作代码
- (1) 存和插入操作(增)
- (2) 删除操作(删)
- (3) 修改元素操作(改)
- (4) 获取元素操作(查)
- 3.线性表顺序存储结构的优缺点
- 四.链式存储结构
- 1.顺序存储结构不足的解决办法
- 2.链式存储结构
- 3.单链表
- (1).单链表常用操作代码
- 1.单链表的插入(增)
- 2.单链表的结点删除(删)
- 3.单链表的修改(改)
- 4.单链表的读取(查)
- (2).单链表的插入和删除分析
- (3).单链表结构与顺序存储结构优缺点
- 4.静态链表
- (1).什么是静态链表
- (2).静态链表的组成
- (3).通过Java代码实现静态链表
- 5.循环链表
- (1).什么是循环链表
- (2).循环链的组成
- 6.双向链表
- (1).什么是双向链表
- (2).双向链表的组成
- (3).双向链表的总结
一.大话数据结构电子图书下载地址
大话数据结构下载链接 百度网盘密码:i70v
二.线性表
什么是线性表?
书上的定义:零个或多个数据元素的有限序列。
星座列表是否为一个线性表:是的
某家公司的组织架构是否为线性表:不是的
本章节框架图如下:
线性表有二种物理结构即顺序存储结构和链式存储结构
三.顺序存储结构
1.什么是顺序存储结构?
书中的定义:线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
- 用一段地址连续的存储单元存放数据元素
- 数据元素的数据类型相同
通过上面二点我们可以通过一维数组来实现顺序存储结构:
- 线性表的索引(线性表的索引从1开始,数组从0开始)
- 线性表的抽象数据类型
- 线性表的长度应该小于等于数组的长度
2.顺序存储结构索引表常用操作代码
项目结构:
SequentialStructure.java
package lineartable;import org.omg.CORBA.IdentifierHelper;public class SequentialStructure<T> {// 数组的容量public final int maxSize;// 数组private T[] array;// 数据长度public int length;// 初始化线性表(对应抽象数据类型表中的InitList(*L))@SuppressWarnings("unchecked")public SequentialStructure(int maxSize) {// 初始化容量this.maxSize = maxSize;// 创建一个空的线性表array = (T[]) new Object[this.maxSize];// 初始化数据长度为0this.length = 0;}// insert:插入数据(对应抽象数据类型表中的ListInsert(*L,i,e))public boolean insert(int index, T data) {// 线性表中数据已满if (this.length == this.maxSize) {throw new RuntimeException("插入数据失败:线性表中数据已满!");}// 插入的位置有误if (index > this.length + 1 || index < 1) {throw new RuntimeException("插入数据失败:插入的位置不在线性表范围内!");}// 插入的数据不在表尾if (index <= this.length) {// 将要插入位置后的数据元素向后移动一位for (int i = this.length; i >= index - 1; i--) {array[i + 1] = array[i];}}array[index - 1] = data;this.length++;return true;}public boolean insert(T data) {// 线性表中数据已满if (this.length == this.maxSize) {throw new RuntimeException("插入数据失败:线性表中数据已满!");}array[this.length] = data;this.length++;return true;}// 查找线性表指定索引位置上的数据public T getElem(int index) {if (index < 1 || index > this.length || this.length == 0) {return null;}return array[index - 1];}// 删除线性表上指定索引位置上的数据public boolean delete(int index) {if (this.length == 0) {return false;}if (index < 1 || index > this.length) {throw new RuntimeException("删除数据失败:删除的位置不在线性表范围内!");}// 删除的时候不在末尾,数据要前移if (index < this.length) {for (int i = index; i < this.length; i++) {array[i - 1] = array[i];}}this.length--;return true;}// 修改数据元素public boolean update(int index, T data) {if (this.length == 0) {return false;}if (index < 1 || index > this.length) {throw new RuntimeException("修改数据失败:修改的位置不在线性表范围内!");}array[index - 1] = data;return true;}}
(1) 存和插入操作(增)
- 不带索引增操作(存操作)
Java代码如下:
关于不带索引增操作的算法复杂度:
最坏情况复杂度为:O(1)
平均复杂度:O(1)
- 带索引增操作(插入操作)
插入算法思路:
Java代码实现如下:
关于数据元素后移:
从最后面的元素开始依次向后移动
然后将数据插入到指定位置上即可
运行效果:
关于带索引增操作的算法复杂度:
最坏情况复杂度为:O(n)
平均复杂度:O(n-1/2)=O(n)
(2) 删除操作(删)
删除算法思路:
Java代码实现如下:
关于数据前移:
从离索引最近的一个元素开始依次向前移
将最后一个元素移除
运行效果:
关于删除操作的算法复杂度:
最坏情况复杂度为:O(n)
平均复杂度:O(n-1/2)=O(n)
(3) 修改元素操作(改)
Java代码如下:
运行效果:
关于修改元素的算法复杂度:
最坏情况复杂度为:O(1)
平均复杂度:O(1)
(4) 获取元素操作(查)
线性表索引从1开始,而数组从0开始所以获取线性表指定索引上的元素需要索引要减1
Java代码实现如下:
关于获取元素操作的算法复杂度:
最坏情况复杂度为:O(1)
平均复杂度:O(1)
3.线性表顺序存储结构的优缺点
四.链式存储结构
1.顺序存储结构不足的解决办法
2.链式存储结构
书中的定义:
3.单链表
书中的定义:
数据域: 存储数据元素信息的域
指针域: 存储一个指示其直接后继的信息(即直接后继的存储位置)
对于线性表来说,总得有个头有个尾,链表也不例外。我们把链表中第一个结点的存储位置叫做头指针,那么整个链表的存取就必须是从头指针开始进行了。之后的每一个结点,其实就是上一个的后继指针指向的位置。想象一下,最后一个结点,它的指针指向哪里?
最后一个,当然就意味着直接后继不存在了,所以我们规定,线性链表的最后一个结点指针为“空”(通常用 NULL 或“^”符号表示,如图3-6-3所示)。
有时,我们为了更加方便地对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点,头结点的数据域可以不存储任何信息,也可以存储如线性表的长度等附加信息,头结点的指针域存储指向第一个结点的指针,如图3-6-4所示。
关于头指针与头结点的异同?
(1).单链表常用操作代码
线性表链式存储结构代码描述:
- 若线性表为空表,则头结点的指针域为“空”,如图3-6-6所示。
- 单链表的存储示意图
- 带有头节点的单链表示意图
- 空链表示意图
通过Java代码实现单链表,下面介绍几种常用操作:
项目结构:
Node.java(用于表示结点)
SingleLink.java
package singlelinkedlist;public class SingleLink<T> {private Node<T> head;// 链表的头节点private Node<T> last;// 链表的尾节点public int length = 0;// 节点数量public SingleLink() {this.head = null;this.last = null;}public SingleLink(T data) {this.head = new Node<T>(data);this.last = this.head;length++;}// 头结点尾插入public boolean insert(T data) {Node<T> newNode = new Node<T>(data);// 一个结点都没有,将当前结点设为头结点if (this.length == 0) {this.head = newNode;this.last = newNode;} else {// 已经有头结点了,增加新节点this.last.next = newNode;this.last = newNode;}length++;return true;}// 头结点前插入public boolean insertHead(T data) {if (this.length == 0) {return insert(data);}Node<T> temp = this.head;this.head = new Node<T>(data);this.head.next = temp;length++;return true;}// 从指定位置插入@SuppressWarnings("unused")public boolean insert(int index, T data) {if (index < 0) {throw new IndexOutOfBoundsException("索引越界:" + index);}// 插入的位置在头部if (index == 0) {return insertHead(data);} else if (index >= this.length || this.length == 0) {// 插入的位置在尾部return insert(data);} else {// 插入中间Node<T> upNode=this.head;Node<T> currentNode=upNode.next;int j=1;while(currentNode!=null && j<index){upNode=currentNode;currentNode=upNode.next;}Node<T> newNode=new Node<T>(data);upNode.next=newNode;newNode.next=currentNode;length++;}return true;}// 获取结点数据public T getElem(int index) {// 判断查询的索引是否越界if (index < 0 || index > this.length) {throw new IndexOutOfBoundsException("索引越界:" + index);}// 获取头结点Node<T> hNode = this.head;int i = 1;while (hNode != null && i <= index) {hNode = hNode.next;++i;}return hNode.data;// 返回index对应结点的数据}// 从尾节点删除@SuppressWarnings("unchecked")public boolean deleteLast() {if (this.length == 0) {// 没有元素。删除失败,抛出异常throw new RuntimeException("删除失败,没有元素删除!");}if (length == 1) {// 只有一个元素,头尾元素相同,直接删除this.head = null;this.last = null;} else {// 含义多个元素@SuppressWarnings("rawtypes")Node lastNode = head;// lastNode.next不会空指针就执行完毕,以为last存在while (lastNode.next != this.last) {lastNode = lastNode.next;}this.last = lastNode;this.last.next = null;}length--;return true;}// 从指定位置删除public boolean delete(int index) {if (this.length == 0) {// 没有元素。删除失败,抛出异常throw new RuntimeException("删除失败,没有元素删除!");}if (index < 0 || index > this.length - 1) {// 下标越界throw new IndexOutOfBoundsException();}if (index == 0) {// 删除头部return deleteHead();} else if (index == this.length - 1) {// 删除尾部return deleteLast();} else {// 删除中间,至少有3个元素// 上一个元素Node upNode = this.head;// 当前元素Node currentNode = upNode.next;// 下一个元素Node downNode = currentNode.next;int j = 1;while (currentNode != null && j < index) {upNode=currentNode;currentNode=upNode.next;downNode=currentNode.next;++j;}upNode.next=downNode;length--;return true;}}// 删除头部元素public boolean deleteHead() {if (this.length == 0) {// 没有元素。删除失败,抛出异常throw new RuntimeException("删除失败,没有元素删除!");}if (length == 1) {// 只有一个元素,头尾元素相同,直接删除this.head = null;this.last = null;} else {// 含义多个元素Node<T> currect = this.head.next;this.head = currect;}length--;return true;}// 修改结点数据public boolean update(T data,T newData) {Node<T> tempNode=this.head;while(tempNode!=null){if (tempNode.data.equals(data)) {tempNode.data=newData;return true;}tempNode=tempNode.next;}return false;}}
1.单链表的插入(增)
头结点尾插入
有二种情况,情况一单链表中没有头结点,插入的数据就是头结点,情况二单链表中有头结点,从尾节点插入,尾结点的指针域指向新结点,然后将新结点设为尾节点。
Java代码如下:头结点前插入
有二种情况,情况一单链表中没有头结点,插入的数据就是头结点,情况二单链表中有头结点,从头结点处插入,插入的数据就是头结点,然后当前头结点指针域指向以前的头结点。
Java代码如下:
指定位置插入
有三种情况,情况一从头结点处插入(index=0),情况二从尾节点处插入(index>=this.length(单链表的长度)),情况三从结点中间插入。
从结点中间插入,通过下面的例子来理解:
需求:
创建一个单链表
创建四个结点(包括头结点),结点数据分别为1,3,4,5
在结点1和结点2之间插入一个新结点(该结点data为2)
在结点1和结点2之间插入新结点只需要将插入位置上的结点前一个结点指向新的结点,新的结点指向该位置下一个结点。指针指向情况如下:
插入之后的指针指向情况如下
Java代码如下:
要实现上面的操作,只需要知道指定位置上的结点和该结点上一结点,然后再修改指向,创建二个结点(当前位置结点(默认为头结点的下一结点),当前位置上一结点(默认为头结点))通过当前位置结点依次向尾结点移动,直到当前结点到达指定位置停止,在移动的过程中当前位置结点和上一结点都会依次变化,最后再修改指针指向。
Java代码如下:
2.单链表的结点删除(删)
从头部元素删除
有三种情况,情况1一个结点都没有,提示用户删除失败,情况2只有一个结点,头尾结点相同,直接删除,情况3有多个结点,只需要获取头结点的下一个结点然后将该结点设为头结点即可。
Java代码如下:从尾节点删除
有三种情况前面二种情况和从头部元素删除的前二种情况是相同的,最后一种情况,通过获取尾结点前一个结点,然后将该结点设为尾节点即可。
Java代码如下:
从指定位置删除
有三种情况,从头部元素删除,从尾节点删除和从中间结点删除,从中间结点删除思路和前面插入思路差不多。
只需要获取要删除位置的前一个结点和后一个结点,然后将前一个结点的指针指向下一个结点(前一个结点和后一个结点的获取和前面思路一致)。
Java代码如下:
3.单链表的修改(改)
从当前结点开始依次向下一个结点移动,直到有要修改值为止,然后将旧值修改成新值。
Java代码如下:
4.单链表的读取(查)
从当前结点开始依次向下一个结点移动,直到i<=index,然后返回当前index的结点。
Java代码如下:
分析:
(2).单链表的插入和删除分析
(3).单链表结构与顺序存储结构优缺点
4.静态链表
(1).什么是静态链表
问题:
解决办法:
答:用数组描述链表叫做静态链表
(2).静态链表的组成
(3).通过Java代码实现静态链表
项目来源于:【Java】 大话数据结构(3) 线性表之静态链表
项目结构:
SNode.java(相当于单链表中的结点)
Student.java
StaticLinkList.java
package staticlinklist;public class StaticLinkList<E> {private SNode<E>[] nodes;// 结点数组private int maxSize;public StaticLinkList() {this(1000);}public StaticLinkList(int maxSize) {this.maxSize = maxSize;nodes = new SNode[this.maxSize];// 泛型的数组建立似乎有些问题for (int i = 0; i < this.maxSize - 1; i++) {nodes[i] = new SNode<E>(null, i + 1);}nodes[maxSize - 1] = new SNode<E>(null, 0);}/*** 获取第i个元素的下标*/public int getIndex(int i) {if (i < 1 || i > this.getLength())throw new RuntimeException("查找位置错误!");int k = nodes[maxSize - 1].cur;for (int j = 1; j < i; j++)k = nodes[k].cur;return k;}/*** 获取第i个元素*/public SNode<E> getElement(int i) {return nodes[getIndex(i)];}/*** 返回可分配结点下标*/public int malloc_sll() {int i = nodes[0].cur;nodes[0].cur = nodes[i].cur;// 第i个分量要拿来用了,所以指向下一个分量// 注意,不是nodes[0].cur=nodes[0].cur+1,下一个分量不一定就是下标加一;return i;}/*** 插入操作,i代表第i个位置,而不是下标 注意插入到第一个位置的特殊性*/public void listInsert(int i, E e) {if (i < 1 || i > this.getLength() + 1)throw new RuntimeException("插入位置错误!");if (getLength() == maxSize - 2)throw new RuntimeException("表已满,无法插入!");int j = this.malloc_sll();nodes[j].data = e;int p; 第i-1个元素的下标if (i == 1) {p = maxSize - 1;} else {p = getIndex(i - 1);}nodes[j].cur = nodes[p].cur;nodes[p].cur = j;}/*** 删除第i个位置的结点*/public SNode<E> listDelete(int i) {if (i < 1 || i > getLength())throw new RuntimeException("删除位置错误!");int m = getIndex(i);int p; // 第i-1个元素的下标if (i == 1) {p = maxSize - 1;} else {p = getIndex(i - 1);}nodes[p].cur = nodes[m].cur;free_sll(m);return nodes[m];}/*** 将下标为i元素回收到备用链表中*/public void free_sll(int i) {nodes[i].cur = nodes[0].cur;nodes[0].cur = i;}/*** 返回静态链表的长度*/public int getLength() {int length = 0;int i = nodes[maxSize - 1].cur;while (i != 0) {i = nodes[i].cur;length++;}return length;}}
StaticLinkListTest.java(测试代码)
package staticlinklist;public class StaticLinkListTest {public static void main(String[] args) {StaticLinkList<Student> students = new StaticLinkList<Student>();System.out.println("——————————插入1到5,并读取内容——————————");Student[] stus = { new Student("小A", 11), new Student("小B", 12), new Student("小C", 13), new Student("小D", 14),new Student("小E", 151) };for (int i = 1; i <= 5; i++)students.listInsert(i, stus[i - 1]);System.out.println("表长:" + students.getLength());Student stu;for (int i = 1; i <= 5; i++) {stu = students.getElement(i).data;System.out.println("第" + i + "个位置为:" + stu.name);}System.out.println("——————————删除小B、小E——————————");stu = students.listDelete(2).data;System.out.println("已删除:" + stu.name);stu = students.listDelete(4).data;System.out.println("已删除:" + stu.name);System.out.println("当前表长:" + students.getLength());for (int i = 1; i <= students.getLength(); i++) {stu = students.getElement(i).data;System.out.println("第" + i + "个位置为:" + stu.name);}System.out.println("表长:" + students.getLength());}}
运行效果:
5.循环链表
(1).什么是循环链表
问题:
解决办法:
答:将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表
(2).循环链的组成
- 循环链头结点(循环链表带有头结点的空链表如图3-13-3)
- 对于非空的循环链表就如图3-13-4所示。
上面循环链表存在的问题:
采用尾指针可以很好的将二个循环链表组成一个表:
比如下面的这两个循环链表,它们的尾指针分别是 rearA 和 rearB,如图3-13-6所示。
要想把它们合并,只需要如下的操作即可,如图3-13-7所示。
6.双向链表
(1).什么是双向链表
问题:
解决办法:
答:双向链表(double linked list)是在单链表的每个结点中,再设置一个指向其前驱结点的指针。
(2).双向链表的组成
- 双向链表的循环带头结点的空链表如图3-14-3所示。
- 非空的循环的带头结点的双向链表如图3-14-4所示。
(3).双向链表的总结
大话数据结构学习笔记-第三章线性表相关推荐
- 《Go语言圣经》学习笔记 第三章 基础数据类型
<Go语言圣经>学习笔记 第三章 基础数据类型 目录 整型 浮点数 复数 布尔型 字符串 常量 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语言小白学习笔记, ...
- 2022天勤考研数据结构笔记 第2章 线性表
2022天勤考研数据结构笔记 第2章 线性表(更新中) 第2章 线性表 2.1 结构体定义 2.2 顺序表 2.3 单链表 2.4 双链表 2.5 循环链表 2.6 逆置问题(408重要考点) 第2章 ...
- 机器人导论(第四版)学习笔记——第三章
机器人导论(第四版)学习笔记--第三章 3 操作臂运动学 3.1 引言 3.2 连杆的描述 3.3 连杆连接的描述 3.4 连杆坐标系的定义 3.5 操作臂运动学 3.6 驱动空间.关节空间和笛卡尔空 ...
- 数据结构个人笔记 第三课 顺序表和单链表
数据结构个人笔记 第三课 顺序表和单链表 顺序表的基本操作 插入元素 删除元素 顺序表查找元素 顺序表更改元素 本节总结代码 单链表 链表的节点 头节点.头指针和首元结点 链表的创建(初始化) 本节总 ...
- 《数据结构》c语言版学习笔记——其他链表(线性表的链式存储结构Part2)
线性表的链式存储结构 数据结构系列文章 第三章 循环链表.双向链表 文章目录 线性表的链式存储结构 前言 一.循环链表 (一)定义 (二)尾指针 二.双向链表 (一)定义 (二)代码 总结 前言 提示 ...
- 【课上笔记】第二章 线性表
第二章 线性表 2.1 线性表的逻辑结构 2.1.1线性表的定义 线性表是一种线性结构.线性结构的特点是数据元素之间是一种线性关系,数据元素"一个接一个的排列".在一个线性表中 ...
- 《大话数据结构》笔记——第8章 查找(二)
文章目录 8.6 二叉排序树 8.6.1 二叉排序树查找操作 8.6.2 二叉排序树插入操作 8.6.3 二叉排序树删除操作 8.6.4 二叉排序树总结 8.7 平衡二叉树( AVL树 ) 8.7.1 ...
- 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第三章:简单控件
第 3 章 简单控件 本章介绍了App开发常见的几类简单控件的用法,主要包括:显示文字的文本视图.容纳视图的常用布局.响应点击的按钮控件.显示图片的图像视图等.然后结合本章所学的知识,演示了一个实战项 ...
- 《大话数据结构》笔记——第8章 查找(一)
文章目录 8.1 开场白 8.2 查找概述 8.3 顺序查找 8.3.1 顺序表查找算法 8.3.2 顺序表查找优化 8.4 有序表查找 8.4.1 折半查找 8.4.2 插值查找 8.4.3 斐波那 ...
- Win32学习笔记 第三章 HelloWin 选择自 villager 的 Blog
Win32学习笔记 作者: 姜学哲(netsail0@163.net) 教材: Windows程序设计(第五版)北京大学出版社 [美]Charles Petzold 著 北京博彦科技发展有限公司 ...
最新文章
- MySQL 随笔记录
- 从数据库中导出数据库文档
- PXE+kickstart——实现网络批量装机
- mybatis-generator逆向工程生成boolean字段解决办法
- 2022保密教育线上培训考试参考答案 05
- 2020暨南大学计算机专硕考研经验分享
- 转一篇关于如何改变性格,建立自信的帖子,写的很好,我一定做到,看后才明白自己到底该如何改变
- 工作能力特长归纳总结
- 怎么在手机上取消双重认证_用手机在淘宝上怎么开网店?流程步骤详解
- win7打不开计算机网络连接,win7电脑网络连接正常打不开网页怎么解决
- catkin_make报错: ROS Base path和Source space不一致问题,
- rpmbuild打包任意文件及目录制作为rpm文件
- 微信小程序 image图片组件实现宽度固定 高度自适应
- 理清互联网金融的脉络(二)
- Lightroom无法在卷计算机上,lightroom无法正常启动怎么办?解决lightroom无法启动方法...
- 什么是美国次贷危机,看后你就明白了
- 常用的博客社区(续)
- online boosting 和 batch boosting的区别
- Mac环境下为Python安装MySQLdb库时遇到的诸多问题
- 服务器掉包的原因?103.219.36.x
热门文章
- 【答题卡识别】基于matlab GUI hough变换答题卡判定与成绩统计(带面板)【含Matlab源码 1017期】
- 毕设题目:Matlab飞行器
- 【物理应用】基于matlab GUI工程供配电系统【含Matlab源码 1051期】
- 【图像增强】基于matlab GUI暗通道图像去雾【含Matlab源码 835期】
- 【树叶识别】基于matlab BP神经网络树叶类别【含Matlab源码 799期】
- 【语音合成】基于matlab重叠相加法的信号分帧与还原【含Matlab源码 568期】
- 【情感识别】基于matlab GUI改进的KNN算法语音情感分类识别【含Matlab源码 354期】
- 【行为识别】基于matlab差影法三维人体姿态行为识别【含Matlab源码 277期】
- MySQL中删除表中并不存在的数据不报错
- csv datatable 乱码 导出_C#将DataTable导出到csv文件