数据结构与算法
Posted 执章学长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法相关的知识,希望对你有一定的参考价值。
数据结构与算法
- 1.数组模拟循环队列
- 2. 单链表
- 3. 双链表
- 4. 单向环形链表
- 5. 数组模拟栈(stack)
- 6. 递归
- 6. 排序算法
- 7.查找
- 7.1. 二分查找
- 8. 哈希表
- 9. 二叉树
- 10. 分治算法
- 11.动态规划
- 12. 字符串匹配问题
- 13. 贪心算法
- 14. 额外
1.数组模拟循环队列
1.1. 实现的关键步骤:
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
1.2. 实现代码
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];
2. 单链表
2.1. 实现的关键步骤:
1、需要创建一个节点类(属性包括 数据域 和 指针域 next )
2、需要创建一个链表类(属性包括头节点,初始化链表时,需要创建一个头节点,头节点没有实际意义)
3、增加–找到要插入位置的节点的前一个节点,然后先将节点与后一个节点连接,再将前面的节点连接。关键代码:node.next = temp.next;temp.next = node;
4、删除–找到要删除的节点的前一个节点,然后将引用修改为下下个节点。关键代码:temp.next = temp.next.next;
5、查看–找到要查看的节点并返回。关键代码:return temp;
6、修改–找到要修改的节点,然后修改其值即可。关键代码:temp.值 = 新值;
7、打印链表:先跳过头节点,然后遍历链表直到 temp 指向空时,打印链表的信息。
2.2. 实现代码
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;
2.3. 拓展:
题目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),打印出栈的元素即可。
题目5:合并两个有序的单链表,并且合并之后还是有序的
方法:先创建一个新的头节点,然后创建两个指针指向两个链表的第一个节点(非头节点),然后再创建一个指针记录指向新的头节点(用户每次添加),循环直到有两个链表有一个指针为空为止,当哪个值比较小时,则让新链表的指针指向那个节点,并且新链表向后移动一个,指向的那个节点的指针也要向右移动,退出循环后,要将新链表的指针指向未结束的链表的指针的节点。最后返回头节点。
3. 双链表
3.1. 实现的关键步骤
1、需要创建一个节点类(属性包括 数据域 和指针域 next 和 pre )
2、需要创建一个链表类(属性包括头节点,与单链表类似)
3、增加–节点到链表尾部:与单链表类似,通过遍历,然后连接
4、增加–节点到指定的位置:与单链表类似,找到前一个节点,然后改变指针域
5、删除–可以自我删除,这个是双链表的特点,指针 temp 可以直接指向待删除的节点,然后通过改变指针指向,即可。
6、查看和修改–与单链表类似,直接找到指定的节点进行操作
7、打印链表–与单链表一样
3.2. 实现代码:
package com.cs.testt;
/**
* @ClassName DoubleLinkedListDemo
* @Description TODO
* @Author jiaqi
* @Date 2022/2/23 14:27
* @Version 1.0
**/
//双向链表
public class DoubleLinkedListDemo
class DoubleLinkedList
private TNode head;
public DoubleLinkedList()
this.head = new TNode(0,null,null);
//添加节点到尾部
public void addLast(TNode tNode)
TNode temp = head;
while (true)
if (temp.next == null)
break;
temp = temp.next;
temp.next = tNode;
tNode.pre = temp;
//根据值的大小(从小到大)添加节点
public void addOrder(TNode tNode)
TNode temp = head;
while (true)
if (temp.next == null)
break;
if (temp.next.num >=tNode.num)
break;
temp = temp.next;
if (temp.next == null)
temp.next = tNode;
tNode.pre = temp;
else
//没名字的先来
temp.next一次请求对多条数据进行排序的算法