链表常用操作整理

最近在复习链表的常用操作,顺便整理到博客中方便以后复习。
1.链表定义
对于单向链表来说,包括数据域和指针域,数据域:用于存储数据元素的数值,指针域:指向下一个节点位置。

struct Node {
    int value;
    Node * next;
};

2.常用操作
链表常用操作处理过程中,很重要个一个注意点是在操作过程中不要把链表给处理断了,即找不到next位置。
2.1 插入节点
在链表中的某一个节点p后面插入一个新的节点

//p节点后插入值为i的节点
void insertNode(Node *p, int i) {
    Node* node = new Node;
    node->value = i;
    node->next = p->next;
    p->next = node;
}

2.2 在头节点后插入节点

void insertHeadList(Node *head, int i) {
    Node *node = new Node;
    node->data = i;
    node->next = head;
    head = node;
    printf("insertHeadList函数执行,向表头插入元素成功\n");
}

2.3 删除节点
当需要删除一个节点p时,只需要将p的前一个节点的next赋为p->next,但是由于是单向的,只知道p,无法知道p前一个节点,所以需要转换思路。将p下一个的节点覆盖到p节点即可,这样就等效于将p删除了。

void deleteNode(Node *p) {
    p->value = p->next->value;
    p->next = p->next->next;
}

2.4 删除链表中所有与给定的数值相等的节点
具体分析见LeetCode 203. Remove Linked List Elements
代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
    public:
    ListNode* removeElements(ListNode* head, int val) {
        if(head == NULL)
            return head;
        ListNode* temp = head;
        while(temp->next != NULL) {
            if(temp->next->val == val)
                temp->next = temp->next->next; 
            else
                temp = temp->next;
        }
        return head->val == val ? head->next:head;
    }
};

2.5 翻转链表
a.非递归方式
将链表翻转,本来是1->2->3->4,翻转之后变为4->3->2->1,具体分析见
带有头节点的链表翻转

//单链表的转置,循环方法
Node* reverseByLoop(Node *head) {
    if(head == NULL || head->next == NULL)
        return head;
    Node *pre = NULL;
    Node *next = NULL;
    while(head != NULL) {
        next = head->next;
        head->next = pre;
        pre = head;
        head = next;
    }
    return pre;
}

b.递归方式
对于非递归方式,处理时从链表头到链表尾部,依次处理。而对于递归方式,则是找到末尾节点,从尾到头挨个处理。

//递归的方式进行链表翻转
Node* reverseByRecursion(Node *head) {
    if(head == NULL || head->next == NULL)
        return head;
    Node* new_list = reverseByRecursion(head->next);
    head->next->next = head;
    head->next = NULL;
    return new_list;
}

2.6 找出链表的中间节点
用slow和fast指针标记,slow每次走一步,fast每次走两步,当fast到尾节点时,slow就相当于总长度的一半,即在中间节点。

//找出中间节点
Node* findMidNode(Node* head) {
    Node* slow = head;
    Node* fast = head;
    while (fast->next != NULL && fast->next->next!=NULL) {
        slow = slow->next;
        //每次走一步
        fast = fast->next->next;
        //每次走两步
    }
    return slow;
}

2.7 找出倒数第k个节点
用slow和fast指针标记,fast指针先走k步,然后slow和fast同时走,当fast到达末节点时,slow在fast的前k个节点,即为倒数第k个节点。

//找出倒数第k个节点
Node* findKNode(Node* head,int k) {
    Node *slow = head;
    Node *fast = head;
    while (k-->0) {
        if(fast == NULL) {
            return NULL;
        }
        fast =fast->next;
    }
    while (fast->next != NULL) {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

2.8 删除倒数第K个节点
具体分析见LeetCode 19. Remove Nth Node From End of List
代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
    public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *fast = head;
        ListNode *slow = head;
        while(n-- > 0) {
            fast = fast ->next;
        }
        if(!fast)
            return head->next;
        while(fast != NULL && fast->next != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return head;
    }
};

2.9 合并两个有序的单链表
具体分析见LeetCode题目 LeetCode 21. Merge Two Sorted Lists

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
    public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *head = new ListNode(-1);
        ListNode *temp = head;
        while(l1 != NULL && l2 != NULL) {
            if(l1->val < l2->val) {
                temp->next = l1;
                l1 = l1->next;
            } else {
                temp->next = l2;
                l2 = l2->next;
            }
            temp = temp->next;
        }
        if(l1 != NULL)
             temp->next = l1;
        if(l2 != NULL)
            temp->next = l2;
        return head->next;
    }
};

2.10 判断链表是否有环
设置两个指针slow和fast,slow每次走一步,fast每次走两步。如果slow和fast相遇则存在环。
具体分析见LeetCode 141. Linked List Cycle

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
    public:
    bool hasCycle(ListNode *head) {
        if(head == NULL)
             return false;
        ListNode *fast = head;
        ListNode *slow = head;
        while(fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            if(fast == slow)
                return true;
        }
        return false;
    }
};

2.11 找到链表环的入口点
具体分析以及代码见 LeetCode 142. Linked List Cycle II
2.12 判断两个链表是否相交,并且求相交点
具体分析以及代码见 LeetCode 160. Intersection of Two Linked Lists

Add a Comment

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据