单向链表节点定义
只包含item,和next指针:
单项链表的基本操作
0. 获取链表长度:
public static <T> int length(Node<T> head) {
int length = 0;
while (head != null) {
length++;
head = head.next;
}
return length;
}
1. 在链表头插入节点:
/**
* 在链表首插入节点。将新节点的next指向head,然后让新节点作为head。
* head->Node0
* Node->head->Node0
*/
public static<T> Node<T> insertHead(Node<T> head, T item) {
Node<T> node = new Node<T>(item);
node.next = head;
head = node;
return head;
}
2. 在链表尾插入节点:
/**
* 在链表尾插入节点。链表尾的next指向新节点即可。
* head->null
* head->Node->null
*/
public static<T> void insertTail(Node<T> head, T item) {
while(head.next != null) {
head = head.next;
}
head.next = new Node<T>(item);
}
3. 在链表中间插入节点:
/**
* 在链表中间插入新节点、在两节点中间插入一个新节点,要知道这两个前后节点的指针。
* start->end
* start->mid->end;
* 0 -> 1 -> 2
*/
public static<T> Node<T> insertMid(Node<T> head, int position, T item) {
if (position == 0) {
return insertHead(head, item);
}
Node<T> current = head;
// 得到start节点的指针
while(position > 1) {
current = current.next;
position--;
}
Node<T> node = new Node<T>(item);
// 得到end节点的指针
Node<T> temp = current.next;
current.next = node;
node.next = temp;
return head;
}
4. 删除链表头节点:
/**
* 删除链表首。将head指向head的next即可。
* head->Node->Node->null
*/
public static<T> Node<T> deleteHead(Node<T> head) {
head = head.next;
return head;
}
5. 删除链表尾节点:
/**
* 删除链表尾。将倒数第二个的next置为null即可。
* head->Node->Node->null
*/
public static<T> Node<T> deleteTail(Node<T> head) {
if (head.next == null) {
return null;
}
Node<T> runner = head;
while(runner.next.next != null) {
runner = runner.next;
}
runner.next = null;
return head;
}
6. 删除链表中间节点:
如果不删除尾节点,使用偷龙换凤:
/**
* 删除链表的中间节点。实际上删除待删节点的下一个节点,将待删节点的下一个节点的数据覆盖到待删节点。不能删除尾节点。
* A->Node->B->C
*/
public static<T> void deleteMid(Node<T> node) {
Node<T> temp = node.next.next;
node.item = node.next.item;
node.next = temp;
}
一般解法:
/**
* 删除链表的中间元素。要知道待删节点的前后节点。将前节点的next指向后节点即可。。
* start->Node->end
* 0 -> 1 -> 2
*/
public static<T> void deleteMid(Node<T> head, int position) {
while(position > 1) {
head = head.next;
position--;
}
head.next = head.next.next;
}
7. 找到链表的第k个节点:
/**
* 找到链表中的第k个节点。依次遍历
* head->Node->Node->Node->Node->null;
* 0 -> 1 -> 2 -> 3 -> 4 -> null
*/
public static<T> Node<T> findKth(Node<T> head, int k) {
for (int i = 0; i < k; i++) {
head = head.next;
}
return head;
}
8. 找到链表的中间节点:
奇数个节点:
偶数个节点:
/**
* 找中间节点。快慢指针法,慢指针走一步,快指针走两步。
* 当有偶数个节点时,慢指针走到中间时,快指针指向链表尾:fast.next == null
* head->slow->Node->fast->null;
* 当有奇数个节点时,慢指针走到中间时,快指针指向null:fast == null
* head->Node->slow->Node->Node->null;
*/
public static<T> Node<T> findMid(Node<T> head) {
Node<T> slow = head;
Node<T> fast = head.next;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
9. 找到链表倒数第k个节点:
/**
* 找到链表中的倒数第k个节点。双指针法。
* 快指针为null时,慢指针指向要找的节点。
* head->Node->slow->Node->Node->null;
* 4 -> 3 -> 2 -> 1 -> 0
*/
public static<T> Node<T> findLastKth(Node<T> head, int k) {
Node<T> slow = head;
Node<T> fast = head.next;
for (int i = 0; i <= k; i++) {
fast = fast.next;
}
while(fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
10. 翻转链表:
/**
* 翻转链表。每次翻转一个节点的next指针,要知道前后两个节点。将该节点的next指向之前的节点,runner指向之后的节点。
* 翻转一个指针,断开下一个指针。
*
* A->B->C->D->null
* null<-A B->C->D->null
* null<-A<-B C->D->null
* null<-A<-B<-C D->null
* null<-A<-B<-C<-D
*/
public static<T> Node<T> reverse(Node<T> head) {
Node<T> previous = null;
Node<T> runner = head;
// 四步交换
while(runner != null) {
Node<T> temp = runner.next;
runner.next = previous;
previous = runner;
runner = temp;
}
return previous;
}
11. 交换两个相邻节点:
/**
* 交换链表中两个相邻节点。要知道前一个节点的parent指针。
* parentI->I->J->Node
* 先将I节点的next指向J节点的next:
* parentI->I->Node
* J->Node
* 然后将J节点的next指向I节点:
* parentI->I->Node
* J->I
* 最后将I父节点的next指向J节点 :
* parentI->J->I->Node
* 如果I节点是head时,新建一个dummy节点作为head的父节点。
*/
public static <T> Node<T> swapAdjacent(Node<T> head, int i) {
Node<T> parentI;
Node<T> nodeI;
Node<T> nodeJ;
if (i == 0) {
if (head == null) {
return head;
}
parentI = new Node<T>(null);
parentI.next = head;
} else {
parentI = findKth(head, i - 1);
if (parentI == null || parentI.next == null
|| parentI.next.next == null) {
return head;
}
}
nodeI = parentI.next;
nodeJ = nodeI.next;
nodeI.next = nodeJ.next;
nodeJ.next = nodeI;
parentI.next = nodeJ;
return i == 0 ? parentI.next : head;
}
12. 交换任意两个节点:
/**
* 交换链表中的任意两个节点。现在考虑两节点不相邻情况:
* parentI->I->Node1->parentJ->J->Node2
* 首先将I节点的next指向J节点的next:
* parentI->I->Node2 Node1->parentJ->J->Node2
* 然后将J节点的next指向原来I节点的next:
* parentI->I->Node2 Node1->parentJ->J->Node1
* 然后I节点的父节点指向J节点:
* parentI->J->Node1->parentJ->J I->Node2
* 最后J节点的父节点指向I节点:
* parentI->J->Node1->parentJ->I->Node2
*/
public static <T> Node<T> swap(Node<T> head, int i, int j) {
if (i == j) {
return head;
}
if (i > j) {
int temp = i;
i = j;
j = temp;
}
Node<T> parentI;
if (i == 0) {
parentI = new Node<T>(null);
parentI.next = head;
} else {
parentI = findKth(head, i - 1);
if (parentI == null || parentI.next == null) {
return head;
}
}
Node<T> parentJ = findKth(head, j - 1);
if (parentJ == null || parentJ.next == null) {
return head;
}
Node<T> nodeI = parentI.next;
Node<T> nodeJ = parentJ.next;
Node<T> nextI = nodeI.next;
if (nextI == nodeJ) {
nodeI.next = nodeJ.next;
nodeJ.next = nodeI;
parentI.next = nodeJ;
} else {
nodeI.next = nodeJ.next;
nodeJ.next = nextI;
parentI.next = nodeJ;
parentJ.next = nodeI;
}
return i == 0 ? parentI.next : head;
}