线性数据结构

数据结构

线性结构

数组(顺序存储)

使用一组连续的存储空间存储相同类型的数据


 

数组的插入以及删除操作是低效的

假设数组的长度为n插入数据的位置为i,则要将i~n的数据全部向后移动,效率偏低,删除操作同理。

稀疏数组

当二维数组中只存放了少量数据的时候,可以考虑采用稀疏数组来减少空间的使用

  1. 记录二维数组中的有效数据个数记作n

  2. 记录每个有效数据的坐标

  3. 创建[n+1] [3]大小的稀疏数组(第一行记录原数组大小以及有效数据,其余行记录有效数据坐标以及值)

  4. 根据稀疏数组还原二维数组

链表(链式存储)

使用不连续的内存空间动态的存储数据


单向链表(包含头节点和不包含头节点的,视情况而定),本文为包含头节点

前奏:定义一个节点,包含数据域和指针域(链接下一个节点--next)

定义一个单向链表,包含一个头节点(无任何实际作用,仅作标识)

增加节点

  • 因为头节点无法移动所以借助辅助节点指向头节点(Help节点)

  • 直接插入:插入条件(当Help节点的下一个节点为空时,让Help节点的next指向插入的节点)

  • 按序插入:插入条件(当Help节点的下一个节点序号大于插入节点的序号时,让插入节点的next指向Help节点的next,Help节点的next指向插入节点)

  • 当条件不满足时,让Help节点等于Help的下一个节点

修改节点

  • 让Help节点指向头节点的下一个节点

  • 修改条件(当Help节点的序号的等于修改节点的序号时)

  • 修改节点数据

  • 当条件不满足时,让Help节点等于Help的下一个节点

删除节点

  • 让Help节点指向头节点的下一个节点

  • 删除条件(Help节点的下一个节点序号等于删除节点的序号)让Help节点的next指向待删除节点的next

  • 当条件不满足时,让Help节点等于Help的下一个节点

遍历链表

  • 定义Help节点指向头节点的下一个节点

  • 结束条件(Help节点的下一个节点为空)

  • 循环打印

双向链表

单向链表双向链表
data,next指针 data,next,pre指针
只能从前往后遍历链表 能够双向遍历链表
不能自我删除节点 能够自我删除节点

前奏:定义一个节点,包含数据域和指针域(链接下一个节点--next和上一个节点--pre)

定义一个双向链表,包含一个头节点(无任何实际作用,仅作标识)

增加节点

  • 因为头节点无法移动所以借助辅助节点指向头节点(Help节点)

  • 直接插入:插入条件(当Help节点的下一个节点为空时,让Help节点的next指向插入的节点,插入节点的pre指向Help节点)

  • 按序插入:插入条件(当Help节点的下一个节点序号大于插入节点的序号时,让插入节点的next指向Help节点的next,Help节点的next指向插入节点,插入节点的pre指向Help节点的next的pre,Help节点的next的pre指向插入节点)

  • 当条件不满足时,让Help节点等于Help的下一个节点

修改节点

  • 让Help节点指向头节点的下一个节点

  • 修改条件(当Help节点的序号的等于修改节点的序号时)

  • 修改节点数据

  • 当条件不满足时,让Help节点等于Help的下一个节点

删除节点

  • 让Help节点指向头节点的下一个节点

  • 删除条件(Help节点序号等于删除节点的序号)Help节点的pre的next指向Help节点的next,Help节点的next的pre指向Help节点的pre(此处要判断Help节点的next是否为空,防止删除最后一个节点时空指针)

  • 当条件不满足时,让Help节点等于Help的下一个节点

遍历链表

  • 定义Help节点指向头节点的下一个节点

  • 结束条件(Help节点的下一个节点为空)

  • 循环打印

josephu(约瑟夫问题)

题目描述:有n个小孩围成一圈,从第i个小孩开始报数,数到s的小孩出队,得到出队的顺序

Josephu

队列

特点:先进先出

使用数组模拟队列

数组模拟队列

栈

特点时先进后出

应用场景

  • 子程序调用时,先将下个指令的地址存储在堆栈中,方便执行完子程序后回到原来程序中

  • 递归调用,和子程序调用相同,不同点在于会将参数和区域变量存储在堆栈中

  • 表达式的转换(中缀表达式转后缀表达式)

  • 二叉数的遍历

  • 图的深度优先遍历算法

使用链表模拟栈

public class LinkedStack
{
public static void main(String[] args)
{
LStack stack=new LStack();
Scanner sc=new Scanner(System.in);
String choice;
boolean loop=true;
while(loop) {
System.out.println("输入push添加数据");
System.out.println("输入pop弹出数据");
System.out.println("输入peek查看栈顶数据");
System.out.println("输入show查看数据");
System.out.println("输入e推出");
choice=sc.next();
switch(choice) {
case "push":
System.out.println("请输入数据");
int value=sc.nextInt();
stack.push(value);
break;
case "pop":
stack.pop();
break;
case "peek":
stack.peek();
break;
case "show":
stack.show();
break;
case "e":
loop=false;
break;
}
}
}
}
​
//定义链表节点对象
class Node{
private int value;
private Node next;

public Node(int value) {
this.value=value;
}
​
public Node getNext()
{
return next;
}
​
public void setNext(Node next)
{
this.next = next;
}
​
public int getValue()
{
return value;
}
​
public void setValue(int value)
{
this.value = value;
}
​
@Override
public String toString()
{
return "Node [value=" + value + "]";
}


}
​
//使用链表模拟栈
class LStack{
private Node head;
//判断栈空
public boolean isEmpty() {
return head==null;
}
//压栈
public void push(int value) {
if(head==null) {
//栈顶没数据
Node node=new Node(value);
head=node;
}else {
//栈顶存在数据
Node node=new Node(value);
node.setNext(head);
head=node;
}
}
//弹栈
public void pop() {
if(isEmpty()) {
//栈空
System.out.println("栈空");
return;
}else {
//栈中有数据
System.out.println(head);
head=head.getNext();
}
}
//展示数据
public void show() {
Node help=head;
if(isEmpty()) {
//栈空
System.out.println("栈空");
return;
}else {
//栈中有数据
while(help!=null) {
System.out.println(help);
help=help.getNext();
}
}
}
//查看栈顶
public int peek() {
if(isEmpty()) {
//栈空
throw new RuntimeException("栈空");
}else {
//栈中有数据
int value=head.getValue();
System.out.println(value);
return value;
}

}
}

栈实现综合计算器(不包括括号和小数点)

思路:

  • 定义两个栈。一个数字栈,一个符号栈

  • 获取用户输入的数学表达式,遍历数学表达

    • 若为符号

      • 若符号栈为空,则直接入栈

      • 若符号栈不为空

        • 当前符号优先级大于栈顶符号优先级时,直接入栈

        • 当前符号优先级小于栈顶符号优先级时,符号栈弹出一个,数字栈弹出两个做运算,结果存入数字栈,当前符号存入符号栈

    • 若为数字:判断当前数字的下一位是否也为数字

      • 若位符号则直接入栈

      • 若为数字则不入栈拼接长数字继续向后遍历

  • 遍历完整个数学表达式则数字栈中为计算结果

前缀表达式(波兰表达式):操作符位于数字之前

中缀表达式:正常数学表达式

后缀表达式(逆波兰表达式):操作符位于数字之后,符合电脑扫描(从左往右)

逆波兰计算器(不包括小数点)

思路:

  1. 将中缀表达式转换为逆波兰表达式

    • 定义两个栈,一个运算符栈s1,一个中间栈s2

    • 遍历中缀表达式

      • 若为数字,判断下一位是否也是数字

        • 若为数字则不入栈拼接长数字继续向后遍历

        • 若为符号则直接入栈s2

      • 若为符号

        • 括号时

          • s1为空时,直接入栈

          • 当为( 时,直接入栈s1

          • 当为 )时,将s1的所有运算符弹出压入s2中,知道遇见 (

        • 操作符

          • s1为空,直接入栈

          • 当前操作符优先级大于s1栈顶优先级,直接压入s2

          • 当前操作符等级不大于s1栈顶优先级,将s1栈顶弹出压入s2并继续与栈中其余操作符按序比较,当s1为空时,直接入s1

    • 最终将s1中全部弹出压入s2,将s2逆序输出即为后续表达式

  2. 遍历后缀表达式,运算结果

    • 若为数字直接入栈

    • 若为操作符则弹出两个数字进行运算后压入栈中

    • 最后结果即为数学表达式结果

posted @ 2021-02-25 13:16  leo_host  阅读(277)  评论(0)    收藏  举报