一、移除链表元素
让被移除的元素的前一个元素直接指向被移除元素的下一个元素,即可完成元素的移除,同时需要考虑到被移除的是第一个元素,那么它就不存在之前的元素。
1.不使用虚拟头节点
首先考虑头节点为目标元素
while(head != NULL && head -> val == target){
head = head -> next; //记得释放内存
}
cur = head;
while(cur != null && cur -> next != Null){
if(cur ->next-> target == target)//当下一个元素为目标数时,直接由当前节点指向下下个节点
cur -> next = cur -> next -> next;
else cur = cur -> next;
}
return head;
2.使用虚拟头节点
当使用虚拟头节点时,所有节点(包括头节点)都有前一个节点和下一个节点,这样对所有节点的操作变得一致,不需要额外判断头节点
dummy head = new ListNode();
dummy head -> next = head;
cur = dummy head;
while( cur -> next != NULL){
if(cur -> next -> val == target){
cur -> next = cur -> next -> next;
}
else cur = cur-> next;
}
return dummy head -> next;
二、设计链表
统一使用虚拟头节点(使用虚拟头节点方便设置新的头节点)
1.获取第n个节点的数值
LinkedNode* dummy head = new LinkedNode();
dummy head -> next = head;
cur = dummy head -> next;
while( n ){
cur = cur -> next
n--;
}
return cur -> val;
2.头部插入节点
LinkedNode* dummy head = new LinkedNode();
dummy head -> next = head;
cur = dummy head -> next;//先保存好原来的头节点
LinkedNode* newnode = new LinkedNode(val);
newnode -> next = dummy head -> next;
dummy head -> next = newnode;
size++;
3.尾部插入节点
Newnode = new LinkedNode(val)
cur = dummy head;
while(cur -> next !=NULL){
cur = cur -> next;
}
cur -> newnode;
4.在第n个节点前插入节点
newnode = new node(val);
cur = dummy head;
while(n--){
cur = cur -> next;
}
newnode -> next = cur -> next;//先将第n个节点储存好,在设计第n-1个节点
cur -> next = newnode;
size++;
5.删第n个节点
cur = dummy head;
while(n--){
cur = cur -> next;
}
cur -> next = cur -> next -> next;
size--;
三、翻转链表
1.双指针法
cur = head;
pre = NULL;//pre负责新指针
while( cur ){
temp = cur -> next;
cur -> next = pur;
pre = cur;
cur = cur-> temp;
}
return pre;
2.递归写法(原理同上)
reverse(cur,pre){
if(cur == NULL) return pre;
temp = cur -> next;
cur -> next = pre;
return reverse(temp,cur);//不断重复reverse这一动作直到反转完成
}
reverselist(head){
return reverse(head,NULL);
}
四、两两交换链表节点
1.虚拟头节点
dummyhead -> next = head;
cur = dummyhead;
while(cur -> next !=NULL && cur -> next -> next != NULL){ //顺序很重要,因为如果cur ->next为空的话,不存在cur ->next ->next,就会报错
temp = cur -> next//每一次反转记得保存下下下一个节点(未参与反转的节点)和参与反转的节点
temp1 = cur -> next -> next -> next;
cur -> next = cur -> next -> next;
cur -> next -> next = temp;
temp -> next = temp1
cur = cur -> next -> next;
}
return dummyhead -> next;
五、删除链表中倒数第n个节点
利用双指针,先让快指针走n+1步,然后快慢同时走,这样当快指针指到NULL时,慢指针刚好指到倒数第n个之前的呢个节点,便可以进行删除操作。
fast = dummyhead;
slow = dummyhead;
n++;
while(n-- && fast != NULL){
fast = fast -> next;
}
while(fast != NULL){
fast = fast -> next;
slow = slow -> next;
}
temp = slow -> next;
slow -> next =slow -> next -> next;
delete temp;
return dummyhead -> next
六、链表相交
先让长的链表减去短的链表,可以得出两条链表长度的差,先让长的链表往后推进这个差值,然后长短一起向前推进,并判断指针是否相等
curA = headA;
curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB; // 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
int gap = lenA - lenB; // 求长度差
while (gap--) { // 让curA和curB在同一起点上(末尾位置对齐)
curA = curA->next;
}
while (curA != NULL) { // 遍历curA 和 curB,遇到相同则直接返回
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
七、环形链表
1.判断环形链表:定义两个指针,快指针和慢指针,看他们是否相遇。
快指针每次走两步,慢指针每次走一步,快指针就相对于慢指针每次走一步,若相遇,就一定有环。
2.寻找环形链表的入口:假设入口处距离起点为x,入口距离相遇处为y,相遇处距离入口为z
相遇时,慢指针走了x+y,快指针走了x+y+n(y+z)
因为快指针一次走两步,慢指针一次走一步
可以得到2(x+y) = x+y+n(y+z)
x+y = n(y+z) n => 1
x = (n-1)(y+z)+z
可见当一个点从相遇点出发,另一个点从起点出发,一定能在环形入口处相遇。
fast = head;
slow = head;
while(fast != NULL && fast -> next != NULL){
fast = fast ->next->next;
slow = slow->next;
if(fast == slow){
index1 = fast;
index2 = head;
while(index1 != index2){
Index1 = index1->next;
Index2 = index2->next;
}
return index1;
}
return NULL;