public class Node {
int data;
Node next = null;
Node(int data) {
this.data = data;
}
}
import java.util.Hashtable;
public class MyLinkedList {
// 链表头的引用
Node head = null;
/**
* 在链表中加入数据,加入到链表尾
*
* @param data 元素的数据
*/
public void addNode(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
/**
* 删除第index个位置的元素。
*
* @howtodo 首先判断index是否超出范围。
* 在判断index是否是指第一个元素。如果不是,则进行下面的做法。遍历到第index个元素,使得其前一个元素指向index+1个元素。
* @param index
* @return
*/
public Boolean deleteNode(int index) {
if (index < 1 || index > this.length()) {
return false;
}
if (index == 1) {
head = head.next;
return true;
}
int i = 2;
Node preNode = head;
Node curNode = head.next;
while (curNode != null) {
if (i == index) {
preNode.next = curNode.next;
return true;
}
preNode = curNode;
curNode = curNode.next;
i++;
}
return true;
}
/**
* 返回链表的长度
*
* @return
*/
public int length() {
int length = 0;
Node temp = head;
while (temp != null) {
length++;
temp = temp.next;
}
return length;
}
/**
* 对链表进行排序
*
* @howtodo 使用双层循环,求出第i个元素后面的元素的最小值,并进行相应交换。
*/
public Node sortList() {
Node nextNode = null;
int temp = 0;
Node curNode = head;
while (curNode.next != null) {
nextNode = curNode.next;
while (nextNode != null) {
if (curNode.data > nextNode.data) {
temp = curNode.data;
curNode.data = nextNode.data;
nextNode.data = temp;
}
nextNode = nextNode.next;
}
curNode = curNode.next;
}
return head;
}
/**
* 删除链表中的重复数据
*
* @howtodo 创建一个hash表用于记录之前没有出现过的元素。再遍历链表,如果遇到之前出现过的元素,则使其上一个元素指向其直接后继元素。
*/
public void deleteDuplecate() {
Hashtable<Integer, Integer> table = new Hashtable<>();
Node temp = head;
Node pre = null;
while (temp != null) {
if (table.containsKey(temp.data)) {
pre.next = temp.next;
} else {
table.put(temp.data, 1);
pre = temp;
}
temp = temp.next;
}
}
/**
* 删除链表中的方法2
*
* @howtodo 使用双层循环遍历链表,判断当前元素后面的元素是否有重复的,如果有,则删除。
*/
public void deleteDuplecate2() {
Node p = head;
while (p != null) {
Node q = p;
while (q.next != null) {
if (p.data == q.next.data) {
q.next = q.next.next;
} else {
q = q.next;
}
}
p = p.next;
}
}
/**
* 一次遍历找到链表中的第k个元素 注意:需要处理k的无效取值
*
* @howtodo 设置两个指针p1,p2。初始位置它们都指向头节点。后面,对p1进行k-1个位置的移动,
* 接着在对p1,p2进行移动,知道p1到达最后一个节点。此时,p2指向的就是第倒数第k个节点。
*
* @thinking 用两个指针可以固定两个指针间的距离,用于解体。
*
* @param k 位置k
*/
public Node findElement(int k) {
if (k < 1)
return null;
Node p1 = head;
Node p2 = head;
for (int i = 0; i < k - 1 && p1 != null; i++)
p1 = p1.next;
if (p1 == null) {
System.out.println("k超出链表长度");
return null;
}
// 判断p1是否到最后一个节点
while (p1.next != null) {
p1 = p1.next;
p2 = p2.next;
}
return p2;
}
/**
* 反转链表
*
* @howtodo 用三个指针分别指向前一个节点,当前节点,下一个结点,然后遍历链表。每一次遍历对当前访问过的节点进行反转。
*/
public void reverse() {
// 用与保存反转后的链表的头节点
Node pReversedHead = head;
// 用于遍历链表
Node pNode = head;
Node pPrev = null;
while (pNode != null) {
Node pNext = pNode.next;
// 当到最后一个结点时,记录下来。
if (pNext == null) {
pReversedHead = pNode;
}
pNode.next = pPrev;
pPrev = pNode;
pNode = pNext;
}
this.head = pReversedHead;
}
/**
* 从尾到头输出链表中的元素
*
* @howtodo 创建一个栈,然后遍历链表,把元素放进去。最后输出栈里的元素。
*/
public void printListReversely(Node node) {
if (node != null) {
printListReversely(node.next);
System.out.println(node.data + " ");
}
}
/**
* 寻找单链表的中间结点
*
* @howtodo 创建一个快指针和慢指针,遍历链表,快指针走两步,慢指针走一步。当快指针到最后不能走时,此时慢指针指到的一定是中点
* @return
*/
public Node searchMid() {
// 快指针
Node p1 = head;
// 慢指针
Node p2 = head;
while (p1 != null && p1.next != null && p1.next.next != null) {
p1 = p1.next.next;
p2 = p2.next;
}
return p2;
}
/**
* 判断链表是否有环
*
* @howtodo 创建一个快指针和慢指针,遍历链表,快指针走两步,慢指针走一步。如果快指针最后为null,则无环,如果它们相遇,则有环。
* @return
*/
public boolean isLoop() {
Node fast = head;
Node slow = head;
if (fast == null) {
return false;
}
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return !(fast == null || fast.next == null);
}
/**
* 找到环的入口点
*
* @howtodo 链表头与相遇点遍历的第一个相遇点。
* @return
*/
public Node findLoopPort() {
Node slow = head;
Node fast = head;
// 找到相遇点
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast)
break;
}
if (fast == null || fast.next == null) {
return null;
}
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
/**
* 在不知道头指针的情况下删除指定结点
*
* @howtodo 把当前节点的值变成直接后继节点的值,并删除直接后继节点。
* @param n 要删除的节点
* @return
*/
public boolean deleteNode2(Node n) {
if (n == null || n.next == null) {
return false;
}
int temp = n.next.data;
n.next = n.next.next;
n.data = temp;
return true;
}
@Override
public String toString() {
Node temp = head;
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("[");
while (temp != null) {
sBuilder.append(temp.data);
temp = temp.next;
if (temp != null) {
sBuilder.append(", ");
}
}
sBuilder.append("]");
return sBuilder.toString();
}
/**
* 判断链表是否相交
*
* @tip 如果两个链表相交,则从相交的节点开始,后面的节点全部相同
* @howtodo 判断尾节点是否相同
*
* @param n1
* @param n2
* @return
*/
public boolean isIntersect(Node n1, Node n2) {
if (n1 == null || n2 == null) {
return false;
}
while (n1.next != null) {
n1 = n1.next;
}
while (n2.next != null) {
n2 = n2.next;
}
return n1 == n2;
}
/**
* 找到相交的第一个节点
* @howtodo 使遍历两个链表的两个指针起点一致,然后第一次相等的地方就是相交的第一个节点。
* @param n1
* @param n2
* @return
*/
public Node getFirstMeetNode(Node n1, Node n2) {
if (n1 == null || n2 == null)
return null;
Node tail1 = n1;
int length1 = 1;
while (tail1.next != null) {
tail1 = tail1.next;
length1++;
}
Node tail2 = n2;
int length2 = 1;
while (tail2.next != null) {
tail2 = tail2.next;
length2++;
}
if (tail1 != tail2)
return null;
Node t1 = n1;
Node t2 = n2;
if (length1 > length2) {
int d = length1 - length2;
while (d != 0) {
t1 = t1.next;
d--;
}
} else {
int d = length2 - length1;
while (d != 0) {
t2 = t2.next;
d--;
}
}
while (t1 != t2) {
t1 = t1.next;
t2 = t2.next;
}
return t1;
}
}