提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
提示:这里可以添加本文要记录的大概内容:
自学JAVA数据结构笔记,跟学视频为:
黑马程序员Java数据结构与java算法全套教程,数据结构+算法教程全资料发布,包含154张java数据结构图_哔哩哔哩_bilibili
提示:以下是本篇文章正文内容,下面案例可供参考
一、双向链表
1.结点API
类名 Node
构造方法 Node(T t,Node pre,Node next):创建Node对象
成员变量 T item:存储数据
Node next:指向下一个结点
Node pre:指向上一个结点
2.结点实现
//结点类
private class Node{
//存储数据
public T item;
//指向上一个结点
public Node pre;
//指向下一个结点
public Node next;
public Node(T item, Node pre, Node next) {
this.item = item;
this.pre = pre;
this.next = next;
}
}
3.双向链表API
类名 TowWayLinkList
构造方法 TowWayLinkList():创建TowWayLinkList对象
成员方法 1.public void clear():空置线性表
2.publicboolean isEmpty():判断线性表是否为空,是返回true,否返回false 3.public int length():获取线性表中元素的个数
4.public T get(int i):读取并返回线性表中的第i个元素的值
5.public void insert(T t):往线性表中添加一个元素;
6.public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素。
7.public T remove(int i):删除并返回线性表中第i个数据元素。
8.public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则 返回-1。
9.public T getFirst():获取第一个元素
10.public T getLast():获取最后一个元素
成员内部类 private class Node:结点类
成员变量 1.private Node first:记录首结点
2.private Node last:记录尾结点
3.private int N:记录链表的长度
4双向链表实现
package List;
import java.util.Iterator;
public class TowWayLinkList<T> implements Iterable<T> {
//首结点
private Node head;
//最后一个结点
private Node last;
//链表的长度
private int N;
//结点类
private class Node {
//存储数据
public T item;
//指向上一个结点
public Node pre;
//指向下一个结点
public Node next;
public Node(T item, Node pre, Node next) {
this.item = item;
this.pre = pre;
this.next = next;
}
}
public TowWayLinkList() {
last = null;
head = new Node(null, null, null);
N = 0;
}
//清空链表
public void clear() {
last = null;
head.next = last;
head.pre = null;
head.item = null;
N = 0;
}
//获取链表长度
public int length() {
return N;
}
//判断链表是否为空
public boolean isEmpty() {
return N == 0;
}
//插入元素t
public void insert(T t) {
//如果最后一个结点为空
if (last == null) {
//将t值赋值给最后一个结点,并让最后一个结点的前一个结点指向头结点,构成双向链表
last = new Node(t, head, null);
head.next = last;
} else {
//将最后一个结点存储
Node oldLast = last;
//创建新结点并将其置为最后一个结点
Node node = new Node(t, oldLast, null);
oldLast.next = node;
last = node;
}
//长度+1
N++;
}
//向指定位置i处插入元素t
public void insert(int i, T t) {
if (i < 0) {
throw new RuntimeException("位置不合法");
}
//找到位置i的前一个结点
Node pre = head;
for (int index = 0; index < i; index++) {
pre = pre.next;
}
//当前结点
Node curr = pre.next;
//构建新结点
Node newNode = new Node(t, pre, curr);
curr.pre = newNode;
pre.next = newNode;
//长度+1
N++;
}
//获取指定位置i处的元素
public T get(int i) {
if (i < 0 || i >= N) {
throw new RuntimeException("位置不合法");
}
//寻找当前结点
Node curr = head.next;
for (int index = 0; index < i; index++) {
curr = curr.next;
}
return curr.item;
}
//找到元素t在链表中第一次出现的位置
public int indexOf(T t) {
Node n = head;
for (int i = 0; n.next != null; i++) {
n = n.next;
if (n.next.equals(t)) {
return i;
}
}
return -1;
}
//删除位置i处的元素,并返回该元素
public T remove(int i) {
if (i < 0 || i >= N) {
throw new RuntimeException("位置不合法");
}
//寻找i位置的前一个元素
Node pre = head;
for (int index = 0; index < i; index++) {
pre = pre.next;
}
//i位置的元素
Node curr = pre.next;
//i位置的下一个元素
Node curr_next = curr.next;
pre.next = curr_next;
curr_next.pre = pre;
//长度-1;
N--;
return curr.item;
}
//获取第一个元素
public T getFirst() {
if (isEmpty()) {
return null;
}
return head.next.item;
}
//获取最后一个元素
public T getLast() {
if (isEmpty()) {
return null;
}
return last.item;
}
@Override
public Iterator<T> iterator() {
return new TIterator();
}
private class TIterator implements Iterator {
private Node n = head;
@Override
public boolean hasNext() {
return n.next != null;
}
@Override
public Object next() {
n = n.next;
return n.item;
}
}
}
二、快慢指针
1.含义
快慢指针指的是定义两个指针,这两个指针的移动速度一块一慢,以此来制造出自己想要的差值,这个差值可以然 我们找到链表上相应的结点。一般情况下,快指针的移动步长为慢指针的两倍
2.中间值问题
//获取链表中间值
public String getMid(Node<String> first) {
Node<String> slow = first; //慢指针
Node<String> fast = first; //快指针
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow.item;
}
3.判断链表是否有环
//判断链表是否有环
public boolean isCircle(Node<String> first) {
Node<String> slow = first;
Node<String> fast = first;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast.equals(slow)) {
return true;
}
}
return false;
}
4.获取环形链表入口
//获取环形链表入口
public Node getEntrance(Node<String> first) {
Node<String> slow = first;
Node<String> fast = first;
Node<String> temp = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast.equals(slow)) {
temp = first;
continue;
}
if (temp != null) {
temp = temp.next;
if (temp.equals(slow)) {
return temp;
}
}
}
return null;
}
三、约瑟夫问题
1.问题描述
传说有这样一个故事,在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决 定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,第一个人从1开始报数,依次往 后,如果有人报数到3,那么这个人就必须自杀,然后再由他的下一个人重新从1开始报数,直到所有人都自杀身亡 为止。然而约瑟夫和他的朋友并不想遵从。于是,约瑟夫要他的朋友先假装遵从,他将朋友与自己安排在第16个与 第31个位置,从而逃过了这场死亡游戏 。
2.解题思路
1.构建含有41个结点的单向循环链表,分别存储1~41的值,分别代表这41个人;
2.使用计数器count,记录当前报数的值;
3.遍历链表,每循环一次,count++;
4.判断count的值,如果是3,则从链表中删除这个结点并打印结点的值,把count重置为0;
3.代码
package List;
public class JosephusCircle {
//约瑟夫问题
public static void main(String[] args) throws Exception {
//1.构建循环链表
Node<Integer> first = null;
//记录前一个结点
Node<Integer> pre = null;
for (int i = 1; i <= 41; i++) {
//第一个元素
if (i == 1) {
first = new Node(i, null);
pre = first;
continue;
}
Node<Integer> node = new Node<>(i, null);
pre.next = node;
pre = node;
if (i == 41) {
//构建循环链表,让最后一个结点指向第一个结点
pre.next = first;
}
}
//2.使用count,记录当前的报数值
int count = 0;
//3.遍历链表,每循环一次,count++
Node<Integer> n = first;
Node<Integer> before = null;
while (n != n.next) {
//4.判断count的值,如果是3,则从链表中删除这个结点并打印结点的值,把count重置为0;
count++;
if (count == 3) {
//删除当前结点
before.next = n.next;
System.out.print(n.item + ",");
count = 0;
n = n.next;
} else {
before = n;
n = n.next;
}
}
/*打印剩余的最后那个人*/
System.out.println(n.item);
}
}
总结
提示:这里对文章进行总结: