1、front:指向队列的第一个元素
2、rear:指向队列的最后一个元素的后一个位置
3、maxSize:队列的最大容量,可以在初始化时定义;如果没定义,可设置默认值。
4、front 和 rear 的初始值为0
5、判空条件:(rear + 1)% maxSize == front
6、判满条件:rear == front
7、入队:判满、rear指针后移、赋值
8、出队:判空、front指针后移
9、获取队首元素:获取 front 指向的元素
10、打印队列:从 front指向的元素到 front + 队列元素的个数
11、队列元素的个数:(rear + maxSize - front) % maxSize
class ArrayQueue{
// 表示数组的最大容量
private int maxSize;
//front 指向队列的第一个元素
private int front;
//rear 指向队列的最后一个元素的后一个位置
private int rear;
// 模拟队列的数组,用于存放元素
private int[] arr;
public ArrayQueue(int arrMaxSize) {
// 初始化时,front 和 rear的初始值都为0,但由于int 本身默认值为 0 ,因此这里可以不用写
//最大值由外部指定(由于牺牲掉一个位置,所以例如传入4实际上只有3个位置)
maxSize = arrMaxSize;
// 创建数组存储
arr = new int[maxSize];
}
// 判断队列是否满
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
// 判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
// 添加数据到队列
public void addQueue(int n) {
// 判断队列是否满
if (isFull()) {
System.out.println("队列满,不能加入数据~");
return;
}
//直接将数据加入
arr[rear] = n;
//将 rear 后移, 这里必须考虑取模
rear = (rear + 1) % maxSize;
}
// 获取队列的数据, 出队列
public int getQueue() {
// 判断队列是否空
if (isEmpty()) {
// 通过抛出异常
throw new RuntimeException("队列空,不能取数据");
}
// 这里需要分析出 front是指向队列的第一个元素
// 1. 先把 front 对应的值保留到一个临时变量
// 2. 将 front 后移, 考虑取模
// 3. 将临时保存的变量返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
// 显示队列的所有数据
public void showQueue() {
// 遍历
if (isEmpty()) {
System.out.println("队列空的,没有数据~~");
return;
}
// 思路:从front开始遍历,遍历多少个元素
// 动脑筋
for (int i = front; i < front + size() ; i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
// 求出当前队列有效数据的个数
public int size() {
// rear = 2
// front = 1
// maxSize = 3
return (rear + maxSize - front) % maxSize;
}
// 显示队列的头数据, 注意不是取出数据
public int headQueue() {
// 判断
if (isEmpty()) {
throw new RuntimeException("队列空的,没有数据~~");
}
return arr[front];
}
}
1、需要创建一个节点类(属性包括 数据域 和 指针域)
2、需要创建一个链表类(属性包括头节点,初始化链表时,需要创建一个头节点,头节点没有实际意义)
3、增加–找到要插入位置的节点的前一个节点,然后先将节点与后一个节点连接,再将前面的节点连接。关键代码:node.next = temp.next;temp.next = node;
4、删除–找到要删除的节点的前一个节点,然后将引用修改为下下个节点。关键代码:temp.next = temp.next.next;
5、查看–找到要查看的节点并返回。关键代码:return temp;
6、修改–找到要修改的节点,然后修改其值即可。关键代码:temp.值 = 新值;
7、打印链表:先跳过头节点,然后遍历链表直到 temp 指向空时,打印链表的信息。
package com.cs.testt;
import java.util.Scanner;
/**
* @ClassName SingleLinkedListDemo
* @Description TODO
* @Author jiaqi
* @Date 2022/2/22 14:27
* @Version 1.0
**/
public class SingleLinkedListDemo {
public static void main(String[] args) {
SingleLinkedList singleLinkedList = new SingleLinkedList();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("------------------------");
System.out.println("请输入以下字母:");
System.out.println("a(add):添加");
System.out.println("f(find):查找");
System.out.println("u(update):更新");
System.out.println("d(delete):删除");
System.out.println("p(print):打印");
System.out.println("o(out):退出程序");
System.out.println("------------------------");
String next = scanner.next();
if (next.charAt(0) == 'o') {
break;
}
switch (next.charAt(0)) {
case 'a':
System.out.println("请输入要添加的值:");
int item = scanner.nextInt();
singleLinkedList.add(item);
break;
case 'f':
System.out.println("请输入要查找的值:");
int item1 = scanner.nextInt();
Node node = singleLinkedList.find(item1);
if (node == null) {
System.out.println("没有找到对应的值");
} else {
System.out.println("找到的值为:" + node.num);
}
break;
case 'u':
System.out.println("请输入要旧的值:");
int oldN = scanner.nextInt();
System.out.println("请输入要新的值:");
int newN = scanner.nextInt();
boolean update = singleLinkedList.update(oldN, newN);
String s = update ? "更新成功" : "要更新的值根本不存在";
System.out.println(s);
break;
case 'd':
System.out.println("请输入要删除的值:");
int item3 = scanner.nextInt();
Node delete = singleLinkedList.delete(item3);
if (delete == null) {
System.out.println("没有找到对应的值");
} else {
System.out.println("已删除的值为:" + delete.num);
}
break;
case 'p':
String s1 = singleLinkedList.printList();
System.out.println(s1);
break;
default:
System.out.println("-------------------------------");
System.out.println("|您的输入格式有误,请重新输入: |");
System.out.println("-------------------------------");
break;
}
}
System.out.println("程序已退出...");
}
}
//链表类
class SingleLinkedList {
private Node head;
public SingleLinkedList() {
this.head = new Node(0, null);
}
//再链表的尾部添加一个节点
public void add(int num) {
Node temp = head;
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
Node node = new Node(num, null);
temp.next = node;
}
// //根据编号添加一个节点(根据num从小到大排序)
// public void addByOrder(Node node){
// Node temp = head;
// while (true){
// if (temp.next == null){
// break;
// }
// if (temp.next.num >= node.num){
// break;
// }
// temp = temp.next;
// }
//
// node.next = temp.next;
// temp.next = node;
// }
public Node find(int num) {
Node temp = head.next;
while (true) {
if (temp == null) {
break;
}
if (temp.num == num) {
break;
}
temp = temp.next;
}
return temp;
}
public boolean update(int oldnum, int newNum) {
Node temp = head.next;
boolean flag = false;//是否找到旧值
while (true) {
if (temp == null) {
break;
}
if (temp.num == oldnum) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.num = newNum;
}
return flag;
}
public Node delete(int num) {
Node del = null;
Node temp = head;
while (true) {
if (temp.next == null) {//没有要找的节点
break;
}
if (temp.next.num == num) {
del = temp.next;
temp.next = temp.next.next;
break;
}
temp = temp.next;
}
return del;
}
public String printList() {
StringBuffer stringBuffer = new StringBuffer();
Node temp = head.next;
int count = 1;
while (true) {
if (temp == null) {
break;
}
stringBuffer.append("第" + count + "个值: " + temp.num + "\n");
temp = temp.next;
count++;
}
return stringBuffer.toString();
}
//计算节点的个数
public int NodeNum(){
int count = 0;
Node temp = head.next;
while (true){
if (temp == null){
break;
}
temp = temp.next;
count++;
}
return count;
}
//查找单链表中的倒数第k个节点(双指针法)
public Node findOrderByLast(int n){
//设置两个指针
Node temp1 = head.next;
Node temp2 = head.next;
while (true){
if (temp1 == null){
break;
}
if (n<1){
break;
}
temp1 = temp1.next;
n--;
}
while (true){
if (temp1 == null){
break;
}
temp1 = temp1.next;
temp2 = temp2.next;
}
return temp2;
}
//反转链表
public void reserve(Node head){
Node reserveHead = new Node(0,null);
Node temp = head.next;
Node cur;
while (true){
if (temp == null){
break;
}
cur = temp;
temp = temp.next;
cur.next = reserveHead.next;
reserveHead.next = cur;
}
head.next = reserveHead.next;
}
}
//节点类
class Node {
public int num;
public Node next;
public Node(int num, Node next) {
this.num = num;
this.next = next;
}
}
题目1:求一个单链表中节点的个数
方法:先创建一个变量作为计数器存储个数,初始值为 0 ,接着创建临时指针,循环遍历直到指针指向的节点为 null ,计数不断增加,最后跳出循环返回计数器。
题目2:查找单链表中的倒数第k个节点
方法1:双指针法。先让指针1和指针2指向第一个节点,接着指针1先走k个节点,然后让两个指针同时走,知道指针1走到null之后,指针2所指的节点即为所求。
方法2:先求出节点的个数(题目1),然后用节点个数减掉k得到需要走的步数,接着让指针走这么多步,即可。
题目3:单链表的反转。
方法:先创建一个新的头节点,然后遍历链表,当遍历到一个节点时将其放到新的头节点的后面的那个位置(每一个都如此),这样到最后的 temp == null 时停止,此时除了头节点外,其余都为所求,最后将旧的头节点指向新的头节点的下一个节点即可(即:head.next = nowHead.next;),然后head。
题目4:从头到尾打印单链表(不可破坏原先链表的结构)
方法:用栈结构 Stack ,遍历链表,并将每个节点压入栈(stack.push),接着循环栈,当栈不为空时,出栈(stack.pop),打印出栈的元素即可。
合并两个有序的单链表,并且合并之后还是有序的
方法:先创建一个新的头节点,然后创建两个指针指向两个链表的第一个节点(非头节点),然后再创建一个指针记录指向新的头节点(用户每次添加),循环直到有两个链表有一个指针为空为止,当哪个值比较小时,则让新链表的指针指向那个节点,并且新链表向后移动一个,指向的那个节点的指针也要向右移动,退出循环后,要将新链表的指针指向未结束的链表的指针的节点。最后返回头节点。