import java.util.*;
public class ChainTable {
//头结点记录的是链表的长度,这里只演示算法不维护长度
private Node head = new Node(0);
public static void main (String[] args) {
deleteDuplecateMap();
deleteDuplecateWhile();
findElem(20);
reverseIteratively();
printListreversely();
SearchMod();
IsLoopAndFindPort();
}
public void addNode (int data) {
Node node = new Node(data);
//带头结点的单链表,头插法逆序。
//node.setNext(head.getNext());
//head.setNext(node);
//带头节点尾插法,不会改变顺序。
Node tail = head;
while (tail.getNext() != null) {
tail = tail.getNext();
}
tail.setNext(node);
}
//删除链表的指定节点,最后一个节点无法删除
public void deleteNode(Node n){
if (n.getNext() == null) {
return;
}
//交换当前值和后一个元素的值,删除后一个元素
Node next = n.getNext();
int tmp = next.getData();
next.setData(n.getData());
n.setData(tmp);
//删除后一个节点
System.out.println("删除指定节点"+next.getData());
n.setNext(next.getNext());
}
public void printChainTable(){
Node print = head;
while (print.getNext() != null) {
print = print.getNext();
System.out.print(print.getData());
}
System.out.println();
}
//定义链表的结构,内部类
class Node {
private int data;
private Node next = null;
public Node (int data) {
this.data = data;
}
public int getData () {
return this.data;
}
public void setData (int data) {
this.data = data;
}
public Node getNext() {
return this.next;
}
public void setNext(Node next) {
this.next = next;
}
}
//链表去重方法1,使用map
public static void deleteDuplecateMap() {
int[] source = new int[]{5,9,7,5,5,3,1,4,2,8,1,3,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
Set<Integer> set = new HashSet<Integer>();
Node pre = chainTable.head;
while (pre.getNext() != null) {
Node current = pre.getNext();
if (set.contains(current.getData())) {
//删除节点
pre.setNext(current.getNext());
}else{
set.add(pre.getData());
pre = pre.getNext();
}
}
Node delete = chainTable.head.getNext().getNext().getNext();
chainTable.deleteNode(delete);
chainTable.printChainTable();
}
//链表去重方法2,使用双重循环
public static void deleteDuplecateWhile() {
int[] source = new int[]{5,9,7,5,5,3,1,4,2,8,1,3,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
Node pre = chainTable.head;
while(pre.getNext() != null){
pre = pre.getNext();
Node p = pre;
while (p.getNext() != null) {
if (p.getNext().getData() == pre.getData()) {
p.setNext(p.getNext().getNext());
} else {
p = p.getNext();
}
}
}
chainTable.printChainTable();
}
//链表取到倒数第K个元素
public static void findElem (int k) {
int[] source = new int[]{5,9,7,3,1,4,2,8,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
//定义两个引用变量,依据两个变量之间的距离k,确定倒数第k个元素,注意这里是有头结点的
Node p1 = chainTable.head.getNext();
Node p2 = chainTable.head.getNext();
//p1引用先走k步,防止空指针异常
for (int i=0;i<k&&p1!=null;i++) {
p1 = p1.getNext();
}
//然后两个指针一起走
while(p1 != null){
p1 = p1.getNext();
p2 = p2.getNext();
}
System.out.println(p2.getData());
}
//实现带头结点的单链表反转,改变指针指向,非递归
public static void reverseIteratively() {
int[] source = new int[]{5,9,7,3,1,4,2,8,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
//单链表反转需要3个引用
Node p1 = chainTable.head.getNext();
Node p2 = p1.getNext();
Node p3 = p2.getNext();
//每3个引用只能交换一次引用,p1和p2之间的引用
p1.setNext(null);
while(p2 != null){
p2.setNext(p1);
//同步后移
p1 = p2;
p2 = p3;
if (p3 != null) {
p3 = p3.getNext();
}
}
//头结点连接回来
chainTable.head.setNext(p1);
chainTable.printChainTable();
}
//逆序输出单链表,用栈的方式或者递归,这里用递归方式
public static void printListreversely () {
int[] source = new int[]{5,9,7,3,1,4,2,8,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
Node p = chainTable.head.getNext();
printReversely(p);
System.out.println();
}
private static void printReversely(Node p) {
if (p != null) {
printReversely(p.getNext());
System.out.print(p.getData());
}
}
//找到链表的中间节点,两个指针速度不一样,即可找到链表中的特定位置的节点
private static void SearchMod () {
int[] source = new int[]{5,9,7,3,1,4,2,8,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
Node p1 = chainTable.head.getNext();
Node p2 = p1;
//三个判断不能少,不然偶数时会找到中间靠后的中间值
while (p1 != null && p1.getNext() != null && p1.getNext().getNext() != null) {
//p1每次移动两位
p1 = p1.getNext().getNext();
p2 = p2.getNext();
}
System.out.println(p2.getData());
}
//判断一个链表是否有环,并且找到环的入口
private static void IsLoopAndFindPort () {
int[] source = new int[]{5,9,7,3,1,4,2,8,6};
ChainTable chainTable = new ChainTable();
for (int i=0; i<source.length; i++) {
chainTable.addNode(source[i]);
}
//构建环
Node p = chainTable.head;
while (p.getNext() != null) {
p = p.getNext();
}
//环的入口在7这个位置
p.setNext(chainTable.head.getNext().getNext().getNext());
//先判断是否为环,快引用和慢引用,速度差2倍,会相遇
Node fast = chainTable.head.getNext();
Node slow = chainTable.head.getNext();
boolean flag = false;
while (fast != null && fast.getNext() != null) {
//第一个节点一定相等,所以
fast = fast.getNext().getNext();
slow = slow.getNext();
if (fast == slow) {
flag = true;
break;
}
}
System.out.println("是否存在环"+flag);
//前提是存在环,如何找到环的如口,一个指针从头开始走,一个指针从fast和slow的交汇点开始走,两个指针相遇则为入口。
Node start = chainTable.head.getNext();
while (start != slow && flag) {
start = start.getNext();
slow = slow.getNext();
}
System.out.println("环的入口为"+start.getData());
}
}
Java数据结构复习——链表
最新推荐文章于 2021-12-31 10:51:58 发布