【数据结构与算法】链表练习题

280 阅读6分钟

0. 引言

链表作为一种基本的数据结构,在我们的工作中,用到的次数非常多。前段时间,在一个简单项目中,用到了双链表。所以当时本着温故而知新的原则,手写双链表的实现。不写不知道,一写吓一跳。居然被链表中的各种指针给搞懵了。所以就在力扣上找了一些链表相关的题。在此记录一下。本次做的链表相关的题目如下,实话实说,我在做第1题设计双链表的时候,卡壳了很久,后面在草稿本上涂涂画画了很久,才写出来。写出来后发现其实也挺简单地,只是刚开始没想明白。推荐大家也从下面的几道题练练手。

1. 设计链表

2. 反转链表

3. 环路检测

4. 合并两个有序链表

5. 合并两个链表

6. 删除链表的节点

7. 链表中倒数第k个节点

1. 设计链表

题目链接: 设计链表

单链表的实现:

typedef struct tagMyLinkedList{
    struct tagMyLinkedList *next;
    int val;
} MyLinkedList;

/** Initialize your data structure here. */
MyLinkedList* myLinkedListCreate() {
    // 这里head作为的是一个带头链表。它本身不存储数据
    MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (head == NULL) {
        return NULL;
    }
    head->next = NULL;
    head->val = 0; // 这里val本来不存储数据,这里复用为链表的长度
    return head;
}

/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
    if (obj == NULL || index < 0 || index >= obj->val) {
        return -1;
    }

    MyLinkedList *tmp = obj->next;
    while (index != 0) {
        tmp = tmp->next;
        index--;
    }
    return tmp->val;
}

/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    if (obj == NULL) {
        return;
    }
    MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (head == NULL) {
        return;
    }
    head->val = val;
    head->next = obj->next;
    obj->next = head;
    obj->val += 1;
    return;
}

/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    if (obj == NULL) {
        return;
    }
    MyLinkedList *tmp = obj;
    while (tmp->next != NULL) {
        tmp = tmp->next;
    }
    MyLinkedList *tail = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (tail == NULL) {
        return;
    } 
    tail->val = val;
    tmp->next = tail;
    tail->next = NULL;
    obj->val += 1;
    return;
}

/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    if (obj->val < index) {
        return;
    } 
    if (obj->val == index) {
        myLinkedListAddAtTail(obj, val);
        return;
    }
    if (index <= 0) {
        myLinkedListAddAtHead(obj, val);
        return;
    }
    MyLinkedList *prev = obj;
    MyLinkedList *current = obj->next;
    while (index != 0) {
        prev = prev->next;
        current = current->next;
        index--;
    }
    MyLinkedList *tmp = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (tmp == NULL) {
        return;
    }
    tmp->val = val;
    tmp->next = current;
    prev->next = tmp;
    obj->val += 1;
    return;
}

/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if (obj == NULL || index < 0 || index >= obj->val) {
        return;
    }
    MyLinkedList *prev = obj;
    MyLinkedList *current = obj->next;
    while (index != 0) {
        prev = prev->next;
        current = current->next;
        index--;
    }
    prev->next = current->next;
    obj->val -= 1;
    return;
}

void myLinkedListFree(MyLinkedList* obj) {
    if (obj == NULL) {
        return;
    }
    MyLinkedList *first = obj;
    MyLinkedList *second = obj->next;
    while (first != NULL) {
        free(first);
        first = second;
        if (second != NULL) {
            second = second->next;
        }
    }
    return;
}

双链表实现:

typedef struct tagMyLinkedList{
    struct tagMyLinkedList *next;
    struct tagMyLinkedList *prev;
    int val;
} MyLinkedList;

/** Initialize your data structure here. */
MyLinkedList* myLinkedListCreate() {
    // 这里head作为的是一个带头链表。它本身不存储数据
    MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (head == NULL) {
        return NULL;
    }
    head->next = NULL;
    head->prev = NULL;
    head->val = 0; // 这里val本来不存储数据,这里复用为链表的长度
    return head;
}

/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
    if (obj == NULL || index < 0 || index >= obj->val) {
        return -1;
    }

    MyLinkedList *tmp = obj->next;
    while (index != 0) {
        tmp = tmp->next;
        index--;
    }
    return tmp->val;
}

/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    if (obj == NULL) {
        return;
    }
    MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (head == NULL) {
        return;
    }
    head->val = val;
    head->next = obj->next;
    if (obj->next != NULL) {
        obj->next->prev = head;
    }
    head->prev = obj;
    obj->next = head;
    obj->val += 1;
    return;
}

/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    if (obj == NULL) {
        return;
    }
    MyLinkedList *tmp = obj;
    while (tmp->next != NULL) {
        tmp = tmp->next;
    }
    MyLinkedList *tail = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (tail == NULL) {
        return;
    } 
    tail->val = val;
    tail->next = NULL;
    tmp->next = tail;
    tail->prev = tmp;
    obj->val += 1;
    return;
}

/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    if (obj->val < index) {
        return;
    } 
    if (obj->val == index) {
        myLinkedListAddAtTail(obj, val);
        return;
    }
    if (index <= 0) {
        myLinkedListAddAtHead(obj, val);
        return;
    }
    MyLinkedList *current = obj->next;
    while (index != 0) {
        current = current->next;
        index--;
    }
    MyLinkedList *tmp = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    if (tmp == NULL) {
        return;
    }
    tmp->val = val;
    MyLinkedList *prev = current->prev;
    tmp->next = current;
    current->prev = tmp;
    prev->next = tmp;
    tmp->prev = prev;
    obj->val += 1;
    return;
}

/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if (obj == NULL || index < 0 || index >= obj->val) {
        return;
    }
    MyLinkedList *current = obj->next;
    while (index != 0) {
        current = current->next;
        index--;
    }
    MyLinkedList *prev = current->prev;
    MyLinkedList *next = current->next;
    prev->next = next;
    if (next != NULL) {
        next->prev = prev;
    }
    free(current);
    current = NULL;
    obj->val -= 1;
    return;
}

void myLinkedListFree(MyLinkedList* obj) {
    if (obj == NULL) {
        return;
    }
    MyLinkedList *first = obj;
    MyLinkedList *second = obj->next;
    while (first != NULL) {
        free(first);
        first = second;
        if (second != NULL) {
            second = second->next;
        }
    }
    return;
}

2. 反转链表

题目链接: 反转链表

实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* reverseList(struct ListNode* head){
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *first = NULL;
    struct ListNode *second = head;
    struct ListNode *third;
    while (second != NULL) {
        third = second->next;
        second->next = first;
        first = second;
        second = third;
    }
    return first;
}

3. 环路检测

题目链接: 环路检测

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode *detectCycle(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return NULL;
    }
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) {
            break;
        }
    }
    if (fast != slow) {
        return NULL;
    }
    slow = head;
    while (slow != fast) {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

4. 合并两个有序链表

题目链接: 合并两个有序链表

递归实现:

    if (l1 == NULL) {
        return l2;
    }
    if (l2 == NULL) {
        return l1;
    }
    if (l1->val > l2->val) {
        l2->next = mergeTwoLists(l1, l2->next);
        return l2;
    }
    l1->next = mergeTwoLists(l1->next, l2);
    return l1;

非递归实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    struct ListNode *dummy = (struct ListNode *)malloc(sizeof(struct ListNode));
    if (dummy == NULL) {
        return NULL;
    }
    struct ListNode *prev = dummy;
    while (l1 != NULL && l2 != NULL) {
        if (l1->val < l2->val) {
            prev->next = l1;
            l1 = l1->next;
        } else {
            prev->next = l2;
            l2 = l2->next;
        }
        prev = prev->next;
    }
    if (l1 == NULL) {
        prev->next = l2;
    } else {
        prev->next = l1;
    }
    return dummy->next;
}

5. 合并两个链表

题目链接: 合并两个链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode *findKthListNode(struct ListNode *list, int k)
{
    struct ListNode *result = list;
    while (result != NULL && k != 0) {
        result = result->next;
        k--;
    }
    if (k != 0) {
        return NULL;
    }
    return result;
}

struct ListNode *getLastListNode(struct ListNode *list)
{
    struct ListNode *prev = list;
    struct ListNode *current = list->next;
    while (current != NULL) {
        prev = current;
        current = current->next;
    }
    return prev;
}

struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2){
    struct ListNode *prevA = findKthListNode(list1, a - 1); // 待删除左节点a的前一个节点
    struct ListNode *currA = prevA->next; // 待删除左节点a
    struct ListNode *currB = findKthListNode(list1, b); // 待删除右节点b
    struct ListNode *lastList2 = getLastListNode(list2); // list2的最后一个节点

    prevA->next = list2;
    lastList2->next = currB->next;
    struct ListNode *tmp1;
    while (currA != currB) {
        tmp1 = currA->next;
        free(currA);
        currA = tmp1;
    }
    free(currB);
    currB = NULL;
    return list1;
}

6. 删除链表的节点

题目链接: 删除链表的节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* deleteNode(struct ListNode* head, int val){
    struct ListNode *dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
    if (dummy == NULL) {
        return NULL;
    }
    dummy->next = head;
    struct ListNode *prev = dummy;
    struct ListNode *current = head;
    while (current != NULL) {
        if (current->val == val) {
            break;
        }
        prev = current;
        current = current->next;
    }
    if (current != NULL) {
        prev->next = current->next;
    }
    return dummy->next;
}

7. 链表中倒数第k个节点

题目链接: 链表中倒数第k个节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int getListSize(struct ListNode *head) {
    int size = 0;
    while (head != NULL) {
        size++;
        head = head->next;
    }
    return size;
}

struct ListNode* getKthFromEnd(struct ListNode* head, int k){
    int size = getListSize(head);
    if (size <= 0 || k > size) {
        return NULL;
    }
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    int i = 0;
    while (i < k) {
        fast = fast->next;
        i++;
    }

    while (fast != NULL) {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}