7.7
数据结构
一、基本概念
-
数据
是指可以进行操作的具体数据,比如0/1
-
数据元素
是数据的基本单位,通常 是被看作一个整体
由多个数据项或者数据元素组成,其实就是一组数据,比如个人的信息(包含年龄、性别)
-
数据结构
各个数据元素之间的关系
三要素
-
逻辑结构
- 集 合
- 线性结构
- 树形结构
- 图状结构(网状结构)
-
物理结构
其实就是存储结构
-
顺序存储
在物理上是连续的
-
链式存储
链表
-
索引存储
有目录记录 数据所在位置
-
散列存储
利用hash值
-
-
数据运算
-
-
数据对象
相同数据结构的集合
-
数据类型
值的集合和定义在这集合上的一组操作
-
抽象数据类型
抽象的数据组织和相关的运算
二、算法
特性:
- 输入
- 输出
- 有穷性
- 确定性
- 可行性
时间复杂度:
-
ps 求导公式:
(x^a)'=ax^(a-1) (a^x)'=a^xlna (logax)'=1/(x*lna) (sinx)'=cosx (cosx)'=-sinx (uv)'=uv'+u'v (u+v)'=u'+v' (u/v)'=(u'v-uv')/v^2
空间复杂度:
-
原地工作
是指算法所需要的空间是常数
三、数据结构
1. 线性表
-
定义
线性表是具有相同类型有限个元素的有限序列
-
分类
-
顺序表
-
相关操作
插入/删除/查找
package com.zxc.linearTable.sequence; /** * 功能描述: 顺序表 * @Author: zxc * @Date: 2020/7/18 12:49 */ public class options { /** * 功能描述: 添加 * @Author: zxc * @Date: 2020/7/17 20:53 */ private int add(int[] t, int i, int e){ for (int j = array.CURRENT_SIZE+1; j != i; j--) { t[j]=t[j-1]; } t[i]=e; return e; } /** * 功能描述: 删除 * @Author: zxc * @Date: 2020/7/18 12:03 */ private void delete(int[] t,int i){ if (i<0||i>array.CURRENT_SIZE){ System.out.println("超出范围"); } for (int j = i; j <array.CURRENT_SIZE ; j++) { t[j]=t[j+1]; } } /** * 功能描述: 展示 * @Author: 31262 * @Date: 2020/7/17 20:52 */ private void display(int[] T){ for (int value : T) { System.out.print(value + " "); } System.out.println(); } public static void main(String[] args) { options os=new options(); int[] t =array.T; os.display(t); os.add(t,2,777); // os.delete(t,2); os.display(t); } }
-
-
单链表
-
头结点是拿来存放想要存放的相关信息,
也是为了统一空表和非空表的相关操作 -
头插法建立单链表
-
尾插法建立单链表
-
插入
前插法:由于需要找到目标元素的前一个元素,所以可能需要遍历链表到前一个,但是前插法可以转成后插法,只需先用后插法再交互元素即可
后插法
-
删除
当给定元素的指针的时候,我们只需要交换元素数据,就可以不用找到前一个元素的指针
-
package com.zxc.linearTable.linkedList; import org.hibernate.validator.constraints.EAN; import java.util.Scanner; /** * 功能描述: 链表 * @Author: zxc * @Date: 2020/7/18 12:48 */ public class options { /** * 功能描述: 创建(头插法 * @Author: zxc * @Date: 2020/7/22 21:32 */ public void createLinkedList(linkedList list){ Node node=list.getNode(); Scanner sr=new Scanner(System.in); String t=""; while(true){ Node newNode=new Node(); t=sr.next(); if (t.equals("x"))break; newNode.setText(t); if (node.getNext()!=null){ newNode.setNext(node.getNext()); } node.setNext(newNode); node=newNode; } } /** * 功能描述: 尾插法 * @Author: zxc * @Date: 2020/7/23 10:47 */ public void createLinkedListByTail(linkedList list){ Node node=list.getNode(); Scanner sr=new Scanner(System.in); String t=""; while(true){ Node newNode=new Node(); t=sr.next(); if (t.equals("x"))break; newNode.setText(t); if (node.getNext()!=null){ newNode.setNext(node.getNext()); } node.setNext(newNode); } } /** * 功能描述: 插入 * @Author: zxc * @Date: 2020/7/22 21:38 */ public linkedList insert(linkedList list,String text,int i){ Node newNode=new Node(text); Node node=list.getNode(); for (int j = 0; j < i-1 && node!=null; j++) { node=node.getNext(); } assert node != null; newNode.setNext(node.getNext()); node.setNext(newNode); return list; } /** * 功能描述: 删除 * @Author: zxc * @Date: 2020/7/22 22:53 */ public linkedList delete(linkedList list,int i){ Node node=list.getNode(); for (int j = 0; j < i-1 && node!=null; j++) { node=node.getNext(); } assert node != null; node.setNext(node.getNext().getNext()); return list; } /** * 功能描述: 展示 * @Author: zxc * @Date: 2020/7/22 22:43 */ public void display(linkedList list){ Node node=list.getNode().getNext(); while (node!=null){ System.out.print(node.getText()+"=>"); node=node.getNext(); } } public static void main(String[] args) { options os=new options(); linkedList list=new linkedList(); os.createLinkedListByTail(list); // os.insert(list,"a",1); // os.insert(list,"b",2); // os.insert(list,"c",3); // os.insert(list,"d",4); // os.insert(list,"e",5); // os.delete(list,2); os.display(list); } }
-
双向链表
- 如单项链表一样操作
-
循环链表(单/双)
- 只是给最后一个数据元素的后继指针指向头指针
package com.zxc.linearTable.doublyLinkedList; import com.zxc.linearTable.doublyLinkedList.Node; import com.zxc.linearTable.doublyLinkedList.linkerList; import java.util.Scanner; /** * 功能描述: 双向链表 * @Author: zxc * @Date: 2020/7/18 12:48 */ public class options { /** * 功能描述: 创建(头插法 * @Author: zxc * @Date: 2020/7/22 21:32 */ public void createLinkedList(linkerList list){ Node node=list.getNode(); Scanner sr=new Scanner(System.in); String t=""; while(true){ Node newNode=new Node(); t=sr.next(); if (t.equals("x")) { break; } newNode.setText(t); newNode.setNext(node.getNext()); newNode.setPre(node); node.setNext(newNode); if (null!=newNode.getNext()){ newNode.getNext().setPre(newNode); } node=newNode; } } /** * 功能描述: 尾插法 * @Author: zxc * @Date: 2020/7/23 10:47 */ public void createLinkedListByTail(linkerList list){ Node node=list.getNode(); Scanner sr=new Scanner(System.in); String t=""; while(true){ Node newNode=new Node(); t=sr.next(); if (t.equals("x"))break; newNode.setText(t); newNode.setNext(node.getNext()); newNode.setPre(node); node.setNext(newNode); if (null!=newNode.getNext()) newNode.getNext().setPre(newNode); } } /** * 功能描述: 插入 * @Author: zxc * @Date: 2020/7/22 21:38 */ public linkerList insert(linkerList list,String text,int i){ Node newNode=new Node(); Node node=list.getNode(); for (int j = 0; j < i-1 && node!=null; j++) { node=node.getNext(); } assert node != null; newNode.setText(text); newNode.setNext(node.getNext()); newNode.setPre(node.getPre()); node.getNext().setPre(newNode); node.setNext(newNode); return list; } /** * 功能描述: 删除 * @Author: zxc * @Date: 2020/7/22 22:53 */ public linkerList delete(linkerList list,int i){ Node node=list.getNode(); for (int j = 0; j < i-1 && node!=null; j++) { node=node.getNext(); } assert node != null; if (node.getNext().getNext()!=null){ node.getNext().getNext().setPre(node); } node.setNext(node.getNext().getNext()); return list; } /** * 功能描述: 展示 * @Author: zxc * @Date: 2020/7/22 22:43 */ public void display(linkerList list){ Node node=list.getNode().getNext(); while (node!=null){ System.out.print(node.getText()+"=>"); node=node.getNext(); } System.out.println(); } public static void main(String[] args) { options os=new options(); linkerList list=new linkerList(); os.createLinkedList(list); os.display(list); os.insert(list,"a",3); // os.insert(list,"b",2); // os.insert(list,"c",3); // os.insert(list,"d",4); // os.insert(list,"e",5); os.delete(list,2); os.display(list); } }
-
静态链表
就是用数组表示链表,
-
常见操作
-
最值
/** * 功能描述: 寻找最小值 * @Author: zxc * @Date: 2020/7/23 13:47 */ public int findMin(linkedList list){ Node node=list.getNode().getNext(); int min=Integer.parseInt(node.getText()); while (node!=null){ if (Integer.parseInt(node.getText())<min){ min=Integer.parseInt(node.getText()); } node=node.getNext(); } return min; } /** * 功能描述: 寻找最大值 * @Author: zxc * @Date: 2020/7/23 13:47 */ public int findMax(linkedList list){ Node node=list.getNode().getNext(); int max=Integer.parseInt(node.getText()); while (node!=null){ if (Integer.parseInt(node.getText())>max){ max=Integer.parseInt(node.getText()); } node=node.getNext(); } return max; }
-
逆置
/** * 功能描述: 逆置 * @Author: zxc * @Date: 2020/7/23 14:16 */ public void reserve(linkedList list){ Node header=new Node(); Node temp; Node node=list.getNode(); while (node.getNext()!=null){ temp=node.getNext(); node.setNext(node.getNext().getNext()); temp.setNext(header.getNext()); header.setNext(temp); } list.setNode(header); }
-
有序归并
/** * 功能描述: 有序归并 * @Author: zxc * @Date: 2020/7/23 14:32 */ public linkedList orderlyMerging(linkedList l1,linkedList l2){ linkedList re=new linkedList(); Node n1=l1.getNode().getNext(); Node n2=l2.getNode().getNext(); Node n3=re.getNode(); int s1=Integer.parseInt(l1.getNode().getText()); int s2=Integer.parseInt(l2.getNode().getText()); for (;n1!=null&&n2!=null;){ if (Integer.parseInt(n1.getText())<Integer.parseInt(n2.getText())){ n3.setNext(n1); n1=n1.getNext(); }else{ n3.setNext(n2); n2=n2.getNext(); } n3=n3.getNext(); } while(n1!=null){ n3.setNext(n1); n1=n1.getNext(); } while(n2!=null){ n3.setNext(n2); n2=n2.getNext(); } return re; }
-
-
2. 栈
-
定义
只允许在一端进行拿/取的数据结构
-
分类
-
顺序存储
利用数组来实现顺序存储元素,再加上一个top指针指向栈顶元素,方便进行进栈、出栈的操作
package com.zxc.stack.linear; /** * 功能描述: 栈 * @Author: zxc * @Date: 2020/7/24 10:56 */ public class options { /** * 功能描述: 初始化顺序空栈 * @Author: zxc * @Date: 2020/7/24 10:57 */ public void initStack(linearStack stack){ stack.top=-1; } /** * 功能描述: 判断栈空 * @Author: zxc * @Date: 2020/7/24 10:59 */ boolean stackEmpty(linearStack s){ return s.top == -1; } /** * 功能描述: 进栈 * @Author: zxc * @Date: 2020/7/24 11:01 */ boolean push(linearStack stack,int x){ if (stack.top==stack.MAX_SIZE-1){ return false; } stack.data[++stack.top]=x; return true; } /** * 功能描述: 出栈 * @Author: zxc * @Date: 2020/7/24 11:09 */ public int pop(linearStack stack){ if (stack.top==-1){ return -1; } return stack.data[stack.top--]; } /** * 功能描述: 展示 * @Author: zxc * @Date: 2020/7/24 11:09 */ public void display(linearStack stack){ for (int i = 0; i <= stack.top; i++) { System.out.print(stack.data[i]+"=>"); } System.out.println(); } /** * 功能描述: 获取栈顶元素 * @Author: zxc * @Date: 2020/7/24 11:18 */ public int getTop(linearStack stack){ return stack.data[stack.top]; } public static void main(String[] args) { linearStack stack=new linearStack(); options os=new options(); os.initStack(stack); os.push(stack,1); System.out.println(os.getTop(stack)); os.push(stack,2); os.push(stack,3); System.out.println(os.getTop(stack)); os.push(stack,4); System.out.println(os.pop(stack)); os.display(stack); } }
tips:共享栈 使用两个指针,相当于是将两个栈的栈底链接起来,能更有效的利用空间,就比如我们拿羽毛球 球桶,可以从底部拿出来
-
链式存储
和链表类似,但是没有头结点,指针直接指向了栈顶元素,方便进行栈顶的元素操作
-
3.队列
-
定义
可以简单理解为,只能在队列一端进行删除,另一端进行插入的表
-
分类
-
顺序存储
还是利用数组来进行实现,可以发现这个和之前讲的栈有点相像,只不过是多了一个队头的指针,
(特别需要注意的是,front指针是队头指针 直接指向队头,rear是队尾指针 直接指向的是队尾元素的后一位,这是为了后续操作的方便性)
这里特别提出来一个问题,当我们不断地进行入栈出栈的操作后,front和rear会不断地被往后推移,最终会导致rear被推到数组的尾部,如下:
-
这就会有小伙伴说,直接判断它溢出不就解决了?当front处于很数组前几位时,的确可以,但是当front也被推送到数组尾部附近时,会造成前面大量空间的浪费(可以称为假溢出)。
为了解决这个问题,引出了循环队列。
也就是把存储队列的顺序队列逻辑上视为环,如下:
那么如何做呢?其实可以通过取余的操作
-
front指针移动
(q.front+1)%MaxSize
-
rear指针移动
(q.rear+1)%MaxSize
-
队列长度
(q.rear-q.front+MaxSize)%MaxSize
判断循环队列是否满/空
因为循环队列,所以队空和队满的情况变得一样,有以下几种解决办法:
- 牺牲一个存储单元
-
增加一个变量代表元素的个数
也就是增加一个位置的数,表示队列所在的元素个数
-
增加tag标识
因为 队列空 是由出队操作引起;
队列满 是由入队操作引起;
所以,我们针对操作后设置一个变量 tag标记该操作是入队还是出队
-
链式存储
一般还是采用带有头结点的队列
tips:有可能的出栈和入栈序列,只需要尝试就好了
-
双端队列
允许两端都允许出队和入队的操作
-
相关应用
- 括号匹配:
- 表达式求值
中缀转后缀,利用栈进行实现
4. 矩阵和数组
数组只需知道它的物理存储地址是连续存储的
下面重点介绍矩阵:
-
定义
矩阵可以简单的理解为二维数组
-
压缩存储
指多个值相同的元素只分配一个空间,对零元素不进行分配
特殊矩阵 是指具有许多的相同矩阵元素或者零元素,且分布具有一定性的规律的矩阵
特殊矩阵的分类:
-
对称矩阵
对于矩阵中的任意元素,都有Aij=Aji
所以对称矩阵只需存储接近一半多一点的元素
-
三角矩阵
对于一个矩阵,上三角或者下三角都是相同的元素,
-
三对角矩阵
-
稀疏矩阵
零元素是非常多的
-
5. 串
-
定义
是由0个或多个字符组成的有序序列,且以\0表示字符串截至
概念 | 解释 |
---|---|
子串 | 在串中的任意个连续的字符 |
-
分类
-
顺序存储
-
堆分配存储
-
块链存储
-
-
串的匹配模式
-
KMP算法
矩阵:
-
定义
矩阵可以简单的理解为二维数组
-
压缩存储
指多个值相同的元素只分配一个空间,对零元素不进行分配
特殊矩阵 是指具有许多的相同矩阵元素或者零元素,且分布具有一定性的规律的矩阵
特殊矩阵的分类:
-
对称矩阵
对于矩阵中的任意元素,都有Aij=Aji[外链图片转存中…(img-IEq5kujS-1595655913307)]
所以对称矩阵只需存储接近一半多一点的元素
-
三角矩阵
对于一个矩阵,上三角或者下三角都是相同的元素,[外链图片转存中…(img-Bnf6fbY6-1595655913308)]
-
三对角矩阵
-
稀疏矩阵
零元素是非常多的
[外链图片转存中…(img-5BqUA0Cl-1595655913309)]
-
5. 串
-
定义
是由0个或多个字符组成的有序序列,且以\0表示字符串截至
[外链图片转存中…(img-QFMAEXy8-1595655913310)]
概念 解释 子串 在串中的任意个连续的字符 -
分类
-
顺序存储
-
堆分配存储
-
块链存储
[外链图片转存中…(img-rtnrjzF0-1595655913311)]
-
-
串的匹配模式
-
KMP算法
6.树
----------------------------------------------------- 在更