数据结构:随机链表的复制,对链表进行插入排序,删除排序链表中的重复元素 II

发布于:2024-12-18 ⋅ 阅读:(31) ⋅ 点赞:(0)

#define _CRT_SECURE_NO_WARNINGS 1
随机链表的复制
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,
该指针可以指向链表中的任何节点或空节点。

  • 在原链表中插入拷贝节点:将每个节点的拷贝插入到原链表中,这样可以在一次遍历中轻松找到每个节点和其拷贝节点的位置关系。
  • 设置拷贝节点的random指针:利用拷贝节点插入原链表后的邻近关系,通过原节点的random指针,快速找到对应的拷贝节点的random
  • 拆解链表:恢复原链表,并同时提取出拷贝链表。

typedef struct Node Node;
struct Node {
    int val;
    struct Node* next;
    struct Node* random;
};

struct Node* copyRandomList(struct Node* head) {
    // 如果链表为空,直接返回NULL
    if (head == NULL)
        return NULL;

    Node* cur = head;
    // 1. 将原链表的每个节点复制一份,插入到原节点后面
    while (cur) {
        // 创建一个新的节点,值和原节点相同
        Node* copy = (Node*)malloc(sizeof(Node));
        copy->next = NULL;
        copy->random = NULL;
        copy->val = cur->val;

        // 获取原节点的下一个节点
        Node* next = cur->next;

        // 将原节点的next指向新节点
        cur->next = copy;

        // 新节点的next指向原节点的下一个节点
        copy->next = next;

        // 移动到下一个原节点
        cur = next;
    }

    // 2. 设置每个复制节点的random指针
    cur = head;
    while (cur) {
        Node* copy = cur->next;
        // 如果原节点有random指针,复制给新节点
        if (cur->random) {
            copy->random = cur->random->next;  // 随机指针指向复制节点
        }
        else {
            copy->random = NULL;  // 如果没有随机指针,设置为NULL
        }
        // 迭代到下一个原节点
        cur = cur->next->next;
    }

    // 3. 拆解链表,恢复原链表并分离出复制链表
    cur = head;
    Node* copyHead = head->next;  // 复制链表的头节点
    while (cur) {
        Node* copy = cur->next;  // 复制节点
        Node* next = copy->next;  // 复制节点的next

        // 恢复原链表的结构:将原节点的next指向下一个原节点
        cur->next = next;

        // 将复制节点的next指向复制链表的下一个节点
        if (next) {
            copy->next = next->next;  // 复制节点的next应该指向复制链表中的下一个节点
        }
        else {
            copy->next = NULL;  // 如果next为空,表示这是链表的最后一个复制节点
        }

        // 迭代到下一个原节点
        cur = next;
    }

    // 返回复制链表的头节点
    return copyHead;
}

对链表进行插入排序
给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。

通过逐步扩展一个已排序部分的链表,将未排序部分的节点按照大小插入到适当位置,确保每一步都保持链表部分有序。

  • 初始状态:将链表的第一个节点视为已排序部分,后续节点逐一插入到该有序链表中。
  • 每步操作:找到当前节点在有序部分中的正确插入位置,并插入。
  • 完成条件:所有节点都被插入到有序链表中。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
struct ListNode* insertionSortList(struct ListNode* head) {
    if (head == NULL || head->next == NULL)
    {
        return head;
    }
    ListNode* sortHead = head;
    ListNode* cur = head->next;
    sortHead->next = NULL;
    while (cur)
    {
        ListNode* next = cur->next;
        //把cur插入到sortHead链表中去,并保持有序
        if (cur->val <= sortHead->val)
        {
            //头插
            cur->next = sortHead;
            sortHead = cur;
        }
        else
        {
            //中间插
            ListNode* sortPrev = sortHead;
            ListNode* sortCur = sortPrev->next;
            while (sortCur)
            {
                if (cur->val <= sortCur->val)
                {
                    sortPrev->next = cur;
                    cur->next = sortCur;
                    break;
                }
                else
                {
                    sortPrev = sortCur;
                    sortCur = sortCur->next;
                }
            }
            //尾插
            if (sortCur == NULL)
            {
                sortPrev->next = cur;
                cur->next = NULL;
            }
        }
        cur = next;
    }
    return sortHead;
}


删除排序链表中的重复元素 II
给定一个已排序的链表的头 head ,删除原始链表中所有重复数字的节点,
只留下不同的数字 。返回 已排序的链表 。

  • 遍历链表

    • 如果当前节点值和下一节点值相等,则跳过这些重复节点。
    • 如果当前节点值不等于下一节点值,则将其保留。
  • 处理重复节点

    • 通过内层循环跳过所有值相同的节点,找到第一个与当前值不同的节点。
    • 更新指针,删除重复的节点。
  • 特殊情况

    • 如果重复节点出现在链表开头,需要更新头指针。
    • 在链表尾部需要检查指针是否为 NULL,防止非法访问。

1.删除中间的情况

2.头相等

3.尾相等

/**

 * Definition for singly-linked list.

 * struct ListNode {

 *     int val;

 *     struct ListNode *next;

 * };

 */

 typedef struct ListNode ListNode;

struct ListNode* deleteDuplicates(struct ListNode* head) {

    if(head==NULL || head->next==NULL)

         return head;

    ListNode* cur=head;

    ListNode* next=cur->next;

    ListNode* prev=NULL;

    while(next)

    {

        if(cur->val!=next->val)//不相等继续往下走

        {

            prev=cur;

            cur=next;

            next=next->next;

        }

        else

        {

            while(next && cur->val == next->val) //对next进行解引用,必须保证next不为空才行

            {

                next=next->next;

            }

            //已经不相等了

            if(prev)

            {

               prev->next=next;

            }

            else

            {

                head=next;

            }

            //释放

            while(cur!=next)

            {

                ListNode* del=cur;

                cur=cur->next;

                free(del);

            }

            if(next)//尾相等的情况下需要判断,不为空才能继续赋值,否则会崩

            {

                next=cur->next;

            }

        }

    }

    return head;

}


网站公告

今日签到

点亮在社区的每一天
去签到