常见的链表题解


struct ListNode
{
    int date;
    struct ListNode* next;
};
//反转链表思路1:
struct ListNode* reverseList(struct ListNode* head)
{
    if (head == NULL);//指针为空
    {
        return NULL;
    }
    ListNode* n1, *n2, *n3;
    n1 = NULL;
    n2 = head;
    n3 = head->next;
    while (n2)
    {
        //反转
        n2->next = n1;
        //迭代
        n1 = n2;
        n2 = n3;
        if(n3)//判断n3不为NULL
        {
            n3 = n3->next;
        }
    }
    //n2为NULL时结束,此时n1为反转后的head
    return n1;//返回
}
//反转链表思路2:头插
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* cur = head;
    struct ListNode* newhead = NULL;
    while (cur)
    {
        struct ListNode* next = cur->next;//记录当前结点指向下一结点的指针
        //头插
        cur->next = newhead;
        newhead = cur;
        //迭代
        cur = next;
    }
    return newhead;
}
//链表的中间结点:
struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode* slow,*fast;
    slow = fast = head;
    while (fast && fast->next)//奇数个fast->next不为NULL,偶数个fast不为NULL
    {
        slow = slow->next;//慢指针走一步
        fast = fast->next->next;//快指针走两步,慢指针走到中间结点,快指针走到尾
    }
    return slow;
}
//找链表的倒数第K个结点
struct ListNode* FindKthToTail(struct ListNode* head,size_t k)
{
    struct ListNode* slow, * fast;
    slow = fast = head;
    //fast先走k个结点
    while (k--)
    {
        if (!fast)//如果fast为NULL,说明k值大于所有元素结点个数(大于链表长度)
        {
            return NULL;
        }
        fast = fast->next;
    }
    //二者同步往后走,fast为NULL时,slow为第k个结点
    while (fast)
    {
        
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}
//合并两个升序链表
struct ListNode* FindKthToTail(struct ListNode* l1, struct ListNode* l2)
{
    if (!l1)//如果l1为空
    {
        return l2;//返回l2
    }
    if (!l2)//如果l2为空
    {
        return l1;//返回l1
    }
    struct ListNode* head = NULL, *tail = NULL;
    while (l1 && l2)//二者不为NULL
    {
        if (l1->date < l2->date)
        {
            if (head == NULL)//头部为空
            {
                head = tail = l1;
            }
            else
            {
                tail->next = l1;//当前tail->next指向l1的结点
                tail = l1;//tail的地址往后移,记录了当前l1结点的位置,方便尾插
            }
            l1 = l1->next;//l1往后移
        }
        else
        {
            if (head == NULL)//头部为空
            {
                head = tail = l2;
            }
            else
            {
                tail->next = l2;//当前tail->next指向l2的结点
                tail = l2;//tail的地址往后移,记录了当前l2结点的位置,方便尾插
            }
            l2 = l2->next;//l2往后移
        }
    }
    if (l1)
        tail->next = l1;
    if (l2)
        tail->next = l2;
    return head;
}
struct ListNode* FindKthToTail(struct ListNode* l1, struct ListNode* l2)
{
    if (!l1)//如果l1为空
    {
        return l2;//返回l2
    }
    if (!l2)//如果l2为空
    {
        return l1;//返回l1
    }
    struct ListNode* head = NULL, * tail = NULL;
    //先确定小的结点做头部
    if (l1->date < l2->date)
    {
        head = tail = l1;
        l1 = l1->next;
    }
    else
    {
        head = tail = l2;
        l2 = l2->next;//l2往后移
    }
    while (l1 && l2)//二者不为NULL
    {
        if (l1->date < l2->date)
        {
            tail->next = l1;//当前tail->next指向l1的结点
            tail = l1;//tail的地址往后移,记录了当前l1结点的位置,方便尾插
            l1 = l1->next;//l1往后移
        }
        else
        {
            tail->next = l2;//当前tail->next指向l2的结点
            tail = l2;//tail的地址往后移,记录了当前l2结点的位置,方便尾插
            l2 = l2->next;//l2往后移
        }
    }
    if (l1)
        tail->next = l1;
    if (l2)
        tail->next = l2;
    return head;
}
//带头链表------------------------
//多一个哨兵位的头结点,这个结点不存储有效数据
struct ListNode* FindKthToTail(struct ListNode* l1, struct ListNode* l2)
{
    if (!l1)//如果l1为空
    {
        return l2;//返回l2
    }
    if (!l2)//如果l2为空
    {
        return l1;//返回l1
    }
    struct ListNode* head = NULL, * tail = NULL;
    //开辟一个哨兵位的头结点
    head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
    while (l1 && l2)//二者不为NULL
    {
        if (l1->date < l2->date)
        {
            tail->next = l1;//当前tail->next指向l1的结点
            tail = l1;//tail的地址往后移,记录了当前l1结点的位置,方便尾插
            l1 = l1->next;//l1往后移
        }
        else
        {
            tail->next = l2;//当前tail->next指向l2的结点
            tail = l2;//tail的地址往后移,记录了当前l2结点的位置,方便尾插
            l2 = l2->next;//l2往后移
        }
    }
    if (l1)
        tail->next = l1;
    if (l2)
        tail->next = l2;
    struct ListNode* list = head->next;//将链表的实际头结点用list接收
    free(head);//释放head哨兵位头结点空间
    return list;//返回头结点
}
//链表的分割
//不能改变链表的已有的相对顺序
struct ListNode* partition(struct ListNode* pHead, int x)
{
    struct ListNode* lessTail, * lessHead, * greaterTail, * greaterHead;
    //创建一个哨兵位的头结点,方便尾插
    //小于X的链表
    lessTail = lessHead = (struct ListNode*)malloc(sizeof(struct ListNode));
    lessTail->next = NULL;
    //大于等于X的链表
    greaterHead = greaterTail = (struct ListNode*)malloc(sizeof(struct ListNode));
    greaterTail->next = NULL;
    struct ListNode* cur = pHead;
    while (cur)
    {
        if (cur->date < x)
        {
            lessTail->next = cur;//将小于X的结点链接在less的链表尾部
            lessTail = cur;//链表尾部往后移
        }
        else
        {
            greaterTail->next = cur; //将大于等于X的结点链接在greater的链表尾部
            greaterTail = cur; //链表尾部往后移
        }
        cur = cur->next;//cur指向下一个待比较的结点
    }
    //所有结点比较结束后,将小于X的链表尾部链接在大于等于X链表的头部,greaterHead->next
    lessTail->next = greaterHead->next;
    //将大于等于X的链表尾部指向空,防止死循环-------------
    greaterTail->next = NULL;
    struct ListNode* newHead = lessHead->next;
    free(lessHead);
    free(lessTail);
    free(greaterHead);
    free(greaterTail);

    return newHead;
}
//判断链表是否为回文结构
bool chPalindrome(struct ListNode* A)
{
    struct ListNode* mid = middleNode(A);
    struct ListNode* rHead = reverseList(mid);
    struct ListNode* curA = A;
    struct ListNode* curR = rHead;
    while (curA && curR)
    {
        if (curA->date != curR->date)
        {
            return false;
        }
        else
        {
            curA = curA->next;
            curR = curR->next;
        }
    }
    return true;
}
//链表相交
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
    struct ListNode* tailA = headA;
    struct ListNode* tailB = headB;
    int lenA = 1;
    int lenB = 1;
    //链表尾部相同,则链表相交,否则不相交
    while (tailA)
    {
        lenA++;//计算链表长度
        tailA = tailA->next;//遍历链表
    }
    while (tailB)
    {
        lenB++;//计算链表长度
        tailB = tailB->next;//遍历链表
    }
    if (tailA != tailB)
    {
        return NULL;
    }
    //计算两个链表长度差值
    int gap = abs(lenA - lenB);//abs绝对值
    //假设A长B短
    struct ListNode* shortList = headA;
    struct ListNode* longList = headB;
    //判断假设是否正确
    if (lenA > lenB)
    {
        shortList = headB;
        longList = headA;
    }
    //长链表先走gap步
    while (gap--)
    {
        longList = longList->next;
    }
    //两个链表同时走
    while (longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;
    }
    //找到交点,返回
    return shortList;
}
//链表是否有环
bool hasCycle(struct ListNode* head)
{
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast&&fast->next)
    {
        slow = slow->next;//慢指针走一步
        fast = fast->next->next;//快指针走两步
        if (fast == slow)
        {
            return true;
        }
    }
    return false;
}
//链表的环的切入点
struct ListNode* EntryNodeOfLoop(struct ListNode* pHead)
{
    struct ListNode* slow = pHead;
    struct ListNode* fast = pHead;
    while (fast && fast->next)
    {
        slow = slow->next;//慢指针走一步
        fast = fast->next->next;//快指针走两步
        if (fast == slow)
        {
            //相遇
            struct ListNode* meet = slow;
            //pHead从起点往后走,meet从相遇点往后走
            //环外长度L = 环长度C - 切点到相遇点的长度X
            //证明:
            //slow 步长 = L+X
            //fast 步长 = L+ N*C +X(N为fast走的患难圈数
            //fast的步长是slow步长的2倍
            //2(L+X) = L+ N*C +X
            //L = N*C -X
            //L = (N-1)*C+ C -X 
            //(N-1)*C 为meet点
            //L = C-X
            
            while (meet != pHead)
            {
                meet = meet->next;
                pHead = pHead->next;
            }
            //二者相遇时
            return pHead;
        }
    }
    //不相遇
    return NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值