写在前面
双向链表
- 单向链表查找的方向只有一个;不能实现自我删除,需要辅助节点
- 双向链表可以向前向后查找,可以实现自我删除
- 一个节点中多出一个
pre
指向前一个节点
代码实现
更新
和展示
跟单链表一样
- 节点,
pre
绑定上一个链表
class Node {
public int id;
public String name;
public Node next;
public Node pre;
}
- 添加,
temp.next
指向node
,node.pre
指向temp
public void add(Node node) {
//头节点不能动,通过辅助节点进行遍历
Node temp = head
while (true) {
//最后一个节点的next指向空
if (temp.next == null) {
break
}
//如果没有找到最后,就将temp后移
temp = temp.next
}
//当退出while循环,temp指向链表的最后
//temp.next指向node,node.pre指向temp
temp.next = node
node.pre = temp
}
- 顺序添加,要注意双向绑定时,添加的位置是不是最后一个,避免空指针异常;要先将后面的接到
添加的node
上,再加node
添加到链表上
public void addByOrder(Node node) {
//通过辅助变量找到插入的位置,位于添加位置的前一个节点
Node temp = head
boolean flag = false
while (true) {
//说明temp已经在最后了
if (temp.next == null) {
break
}
//找到位置,这个位置的后一个id要大于要添加的id
if (temp.next.id > node.id) {
break
} else if (temp.next.id == node.id) {
//添加的id已经存在,不能添加
flag = true
break
}
//后移
temp = temp.next
}
if (flag) {
System.out.println("准备插入的节点已经存在,修改名字")
temp.next.name = node.name
} else {
if (temp.next != null) {
node.next = temp.next
temp.next.pre = node
}
temp.next = node
node.pre = temp
}
}
public void del(int id) {
if (head.next == null) {
System.out.println("List is empty.")
return
}
Node temp = head.next
boolean flag = false
//直接找到待删除的节点
while (true) {
//已经到了链表的最后且没有找到
if (temp == null) {
break
}
if (temp.id == id) {
//找到待删除的节点
flag = true
break
}
temp = temp.next
}
if (flag) {
//待删除的节点的上一个节点的next指向待删除节点的下一个节点
temp.pre.next = temp.next
//待删除的节点的下一个节点的pre指向待删除节点的上一个节点
//有风险,要处理如果待删除的节点是最后一个节点
if (temp.next != null) {
temp.next.pre = temp.pre
}
} else {
System.out.println("没有找到id为" + id + "的节点")
}
}
栈
- 先进后出 FILO-First In Last Out
- 允许插入和删除的一端,是栈顶;固定的一端,是栈底
- 应用场景 子程序的调用;递归调用;表达式转换与求值;二叉树遍历;图形的深度优先搜索法
数组模拟栈
class ArrStack {
private int maxSize;
private int[] stack;
private int top = -1;
public ArrStack(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
public boolean isFull() {
return top == maxSize - 1;
}
public boolean isEmpty() {
return top == -1;
}
public void push(int value) {
if (isFull()) {
System.out.println("Stack is full.");
return;
}
top ++;
stack[top] = value;
}
public int pop() {
if (isEmpty()) {
throw new RuntimeException("Stack is empty.");
}
int value = stack[top];
top --;
return value;
}
public void list() {
if (isEmpty()) {
System.out.println("Stack is empty.");
return;
}
for (int i = top; i >= 0 ; i--) {
System.out.println("stack[" + i + "]=" + stack[i]);
}
}
}
链表模拟栈
class StackLinkedList {
private int maxSize
private Node head = new Node(0)
public StackLinkedList(int maxSize) {
this.maxSize = maxSize
Node cur = null
Node newNode = null
for (int i = 1
newNode = new Node(i)
if (i == 1) {
head.next = newNode
cur = newNode
} else {
cur.next = newNode
cur = newNode
}
}
}
//空
public boolean isEmpty() {
return head.next.flag == false
}
//满
public boolean isFull() {
Node cur = head.next
while (true) {
if (cur.next == null && cur.flag == true) {
return true
}
if (cur.flag == false) {
return false
}
cur = cur.next
}
}
//添加数据
public void push(int value) {
if (isFull()) {
System.out.println("stack is full")
return
}
Node cur = head.next
while (true) {
if (cur.flag == false) {
cur.flag = true
break
}
cur = cur.next
}
cur.value = value
}
//pop
public int pop() {
if (isEmpty()) {
throw new RuntimeException("stack is empty22")
}
Node cur = head.next
while (true) {
if (cur.next != null) {
if (cur.flag == true && cur.next.flag == false) {
break
}
} else {
break
}
cur = cur.next
}
cur.flag = false
return cur.value
}
//list
public void list() {
if (isEmpty()) {
System.out.println("stack is empty33")
return
}
reverseLinkedList()
Node cur = head.next
while (true) {
if (cur.flag == true) {
System.out.println(cur)
}
if (cur.next == null) {
break
}
cur = cur.next
}
}
//反转
public void reverseLinkedList() {
if (head.next == null || head.next.next == null) {
return
}
Node cur = head.next
Node next = null
Node reverseHead = new Node(0)
while (cur != null) {
next = cur.next
cur.next = reverseHead.next
reverseHead.next = cur
cur = next
}
head.next = reverseHead.next
}
}
class Node {
public int value;
public int top;
public Node next;
public boolean flag = false;
public Node(int top) {
this.top = top;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
", top=" + top +
'}';
}
}
栈实现综合计算器
String expression = "30+2*6-7"
//创建两个栈
ArrStack numStack = new ArrStack(10)
ArrStack operStack = new ArrStack(10)
//扫描变量
int index = 0
int num1 = 0
int num2 = 0
int oper = 0
int res = 0
//每次扫描得到的char
char ch = ' '
//拼接多位数
String num = ""
while (true) {
//扫描expression
ch = expression.substring(index, index + 1).charAt(0)
if (operStack.isOperation(ch)) {
if (!operStack.isEmpty()) {
//如果符号栈有操作符,进行比较,如果当前的优先级小于或者等于栈顶的操作符
if (operStack.proiority(ch) <= operStack.proiority(operStack.peek())) {
//就要先从数栈中pop出两个数,从栈pop出操作符进行运算,再存储
num1 = numStack.pop()
num2 = numStack.pop()
oper = operStack.pop()
res = numStack.calculate(num1, num2, oper)
numStack.push(res)
operStack.push(ch)
} else {
//当前优先级大于栈顶
operStack.push(ch)
}
} else {
//符号栈为空直接入栈
operStack.push(ch)
}
} else {
//数字直接入数栈
//numStack.push(ch - 48)
//处理多位数。需要在遍历字符串时,多检测一位,如果是数就继续扫描,并拼接
num += ch
//如果ch是最后一位,直接入栈
if(index == expression.length() - 1) {
numStack.push(Integer.parseInt(num))
} else {
//判断下一个字符是不是数据,如果是数字,就继续扫描,如果运算符则入栈
if (operStack.isOperation(expression.substring(index + 1, index + 2).charAt(0))) {
numStack.push(Integer.parseInt(num))
//清空num
num = ""
}
}
}
//index+1,并判断是否结尾
index ++
if (index >= expression.length()) {
break
}
}
//扫描完,进行剩下的运算
while (true) {
//如果符号栈为空,则计算完成
if (operStack.isEmpty()) {
break
}
num1 = numStack.pop()
num2 = numStack.pop()
oper = (char)operStack.pop()
res = numStack.calculate(num1, num2, oper)
numStack.push(res)
}
System.out.println(expression + " = " + numStack.pop())
}
public int proiority(int operation) {
if (operation == '*' || operation == '/') {
return 1;
} else if (operation == '+' || operation == '-') {
return 0;
} else {
return -1;
}
}
public boolean isOperation(int val) {
return val == '+' || val == '-' || val == '*' || val == '/';
}
public int calculate(int num1, int num2, int operation) {
int res = 0;
switch (operation) {
case '+':
res = num1 + num2;
break;
case '*':
res = num1 * num2;
break;
case '-':
res = num2 - num1;
break;
case '/':
res = num2 / num1;
break;
default:
break;
}
return res;
}
public int peek() {
return stack[top];
}