目录
删除单链表中的节点 Node ,不能遍历
题目解释:不能遍历单链表,题目中已知节点Node
思路:
- 将已知节点的下一个节点信息覆盖到已知节点上。
public void delNode(T value) {
//传入值
findNode(value);
//接收findNode传出来的值
Node<T> p = new Node<>(value);
//链表为空
if (size == 0) {
return;
}else if (size == 1){
head = null;
tail = null;
size--;
}else {
//信息覆盖
p.value = p.next.value;
p.next = p.next.next;
size--;
}
}
两个单链表相交,输出相交节点
思路:
- 设长链表个数有m个,短链表有n个。m>n。首先让长链表遍历m-n个。
- 然后长短链表一起遍历
public Node<T> getMeetNode(SingleLink<T> link){
//this link
//1.先让长链表 先走差值步, 长短链表一起向后遍历 , p ==q ,return p
int curSize = size;
int linksize = link.size;
int diff = curSize - linksize;
Node<T> longLinkP = diff > 0 ? head : link.head;//longLinkP遍历长链表
Node<T> shortLinkP = diff < 0 ?link.head : head; //shortLinkP遍历短链表
//长链表遍历插值步
diff = Math.abs(diff);
while (diff > 0){
longLinkP = longLinkP.next;
diff--;
}
while (longLinkP != shortLinkP){
longLinkP = longLinkP.next;
shortLinkP = shortLinkP.next;
}
return longLinkP;
}
两个单链表分别有序,链表合并为一个有序单链表
思路:
- 将第一个节点最后的next连接到第二个单链表的头结点地址。
public SingleLink<T> orderLink(SingleLink<T> linkOne,SingleLink<T> linkTow){
if (linkOne.size == 0 && linkTow.size == 0){
return null;
}else if (linkOne.size !=0 && linkTow.size == 0){
return linkOne;
}else if (linkOne.size ==0 && linkTow.size !=0){
return linkTow;
}else {
//两者都不为零
//寻找第一个单链表的表尾将next域与第二个单链表的头结点连接起来
linkOne.tail.next = linkTow.head;
return linkOne;
}
}
单链表逆置
思路:
- 申请三个节点分别指定两个为交换地址。
- 另一个为防止链表丢失的指针。
public void reverseLink(){
//this.head
if (head == null || head.next == null){
return;
}
//逆转,节点数>=2
Node<T> p = head,q = p.next,s = q.next;
head.next = null; //原来头结点 -> 尾巴节点
while (q != null){
q.next = p;
p =q;
q = s;
if (s != null){
s = s.next;
}
}
tail = head;//新尾巴用原来head更新
head = p ;//p循环结束 标记 新头部
}
判断一个链表中是否存在环状
思路:
- 定义一个快节点,一个慢节点。
- 快节点追上慢节点证明有环。
public boolean loop(SingleLink<T> link){
//定义两个节点
Node<T> fast = head;
Node<T> slow = head;
//链表为空
if (head == null && tail == null){
return false;
}else {//链表不为空
for (;fast != null;) {
fast = fast.next.next;//快节点
slow = slow.next;//慢节点
if (fast.value.compareTo(slow.value) == 0){
return true;
}else {
return false;
}
}
return false;
}
}
如果链表有环,输出环的入口点
思路:
- 有环,快节点与慢节点有一个相交的节点,重新申请两个结点一个从相交的节点。
- 一个从head节点开始同步遍历,两者相遇节点便为环的入口点。
public Node<T> ringEnter(){
//定义快慢两个节点
Node<T> fast = head;
Node<T> slow = head;
//重新定义一个节点
Node<T> p = head;
//链表为空
if (head == null && tail == null){
return null;
}else {
for (;fast.value.compareTo(slow.value) != 0;) {
fast = fast.next.next;//快节点
slow = slow.next;//慢节点
}
if (fast.value.compareTo(slow.value) == 0) {
for (; p.value.compareTo(slow.value) != 0; ) {
p = p.next;
slow = slow.next;
}
} else {
return null;
}
}
return p;
}
实例变量不存在size, 如何输出倒数第k个节点
提醒:注意时间复杂度。
思路:
- 定义两个变量p和q,首先让p先行遍历k个节点,然后p和q两个节点一起遍历等到p节点遍历到最后一个结点q刚好为倒数第k个节点。
- 遍历。
public Node<T> outPutK(int value){
//定义两个节点
Node<T> p = head;
Node<T> q = head;
int count = 0;//计数器
//链表为空
if (head == null && tail == null){
return null;
}else {
//让p先遍历k个节点
for (;count != value; count++) {
p = p.next;
}
for (;p != null;){
p = p.next;
q = q.next;
}
return q;
}
}
public void show(){
for (Node<T> p = head; p != null ; p = p.next){
System.out.print(p.value);
}
System.out.println();
}