c语言:链表经典算法oj题

目录

问题1:移除链表元素

 方法1:递归删除

 方法2:连续尾插

问题2:链表的中间节点 

方法:快慢指针 

问题3:反转链表

方法: 三指针解法

问题4:合并两个有序链表

方法:比较大小,插入新链表,注意空指针等细节。 

问题5:环形链表的约瑟夫问题

​编辑

方法:环形链表


问题1:移除链表元素

题目链接:OJ链接

题目描述:c语言:链表经典算法oj题_第1张图片 

 方法1:递归删除

情况1:不存在值的情况,返回一个空链表

情况2:头节点要删除,删除完继续返回新的头节点进行判断

情况3:不是情况1,2,不动原来的值,继续下一个节点的判断

最后返回头节点

struct ListNode* removeElements(struct ListNode* head, int val)
{
    // 不存在值的情况,链表为空
    if(head == NULL)
    {
        return NULL;
    }
    // 头节点的值是要删除的值的情况
    if(head->val == val)
    {
        // 新头节点指向下一个节点
        struct ListNode* newhead = head->next;
        // 释放原头节点的内存
        free(head);
        // 头节点赋值为新的头节点
        head = newhead;
        
        // 递归调用函数,去除剩余节点中的值为val的节点
        head = removeElements(head, val);
    }
    else
    {
        // 递归调用函数,去除剩余节点中的值为val的节点
        head->next = removeElements(head->next, val);
    }
    return head;
}

 方法2:连续尾插

先头尾节点置为空,然后传入pcur值,没有pcur值说明停止循环

当不是删除值时

链表为空,头尾节点都指向当前的节点。

链表不为空时,尾插pcur。

是删除值时,pcur走向下一个节点

当尾节点是要删除的值时(且要存在),pcur就不要往下走了,newtail->next=NULL.

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
     // 新链表的头节点和尾节点
     ListNode* newhead, * newtail;
     newhead = newtail = NULL;
     // 当前节点指针
     ListNode* pcur = head;
     // 遍历原链表
     while(pcur)
     {
         // 如果当前节点的值不等于要删除的值
         if(pcur->val != val)
         {
             // 如果新链表的尾节点为空,表示新链表为空
             if(newtail == NULL)
             {
                // 新链表的头尾节点都指向当前节点
                newhead = newtail = pcur;
             }
             else
             {
                 // 将当前节点添加到新链表的尾部
                 newtail->next = pcur;
                 newtail = newtail->next;
             }
         }
         // 指针指向下一个节点
         pcur = pcur->next;
     }
     // 如果新链表的尾节点不为空,将尾节点的next指针置为NULL
     if(newtail)
     {
         newtail->next = NULL;
     }
     // 返回新链表的头节点
     return newhead;
}


问题2:链表的中间节点 

 题目链接:OJ链接

c语言:链表经典算法oj题_第2张图片

方法:快慢指针 

慢指针每次走一步,快指针每次走两步

奇数时,快指针的下一个节点指向NULL时停止,返回慢指针此时位置

偶数时,快指针的节点指向NULL时停止,返回慢指针此时的位置

typedef struct ListNode ListNode; // 定义结构体指针类型 ListNode

struct ListNode* middleNode(struct ListNode* head)
{
ListNode* slow, * fast; // 定义慢指针 slow 和快指针 fast
slow = fast = head; // 将慢指针和快指针都指向链表头部

while (fast && fast->next)  // 当快指针和快指针的下一个节点都不为空时
{
    slow = slow->next;  // 慢指针向后移动一步
    fast = fast->next->next;  // 快指针向后移动两步
}

return slow;  // 返回慢指针,即链表的中间节点
}

注意:不要写成while(fast->next&&fast),因为如果fast为空指针,fast->next便不存在了。会报错


问题3:反转链表

题目链接:OJ链接

c语言:链表经典算法oj题_第3张图片

方法: 三指针解法

创建三个指针

n1指向为空(NULL),n2指向第一个节点,n3指向下一个节点

如果n2不为空,n2节点的指针由指向n3改为指向n1

n1=n2,n2=n3,n3=n3->next

以此类推,直到n2不为空。

typedef struct ListNode ListNode;  // 定义一个别名为ListNode的结构体

struct ListNode* reverseList(struct ListNode* head) 
{
    if(head==NULL)  // 如果头节点为空,则直接返回头节点
        return head;
    
    ListNode* n1, *n2, *n3;  // 定义三个指针n1、n2、n3
    n1 = NULL;  // n1指向NULL,表示反转链表的最后一个节点
    n2 = head;  // n2指向头节点
    n3 = head->next;  // n3指向头节点的下一个节点

    
    while(n2)
    {
        n2->next = n1;  // 将n2的next指针指向n1,实现反转
        n1 = n2;  // 将n2赋值给n1,更新n1的位置
        n2 = n3;  // 将n3赋值给n2,更新n2的位置
        if(n3)
            n3 = n3->next;  // 如果n3不为空,则将n3指向n3的下一个节点
    }
    
    return n1;  // 返回反转后的链表的头节点
}

注意,n3为空就不用往下走了。 


问题4:合并两个有序链表

题目链接:OJ链接

c语言:链表经典算法oj题_第4张图片 

方法:比较大小,插入新链表,注意空指针等细节。 

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
    if(list1==NULL)
    return list2;
    if(list2==NULL)
    return list1;
    ListNode*n1,*n2;
    n1=list1,n2=list2;
    ListNode*newhead,*newtail;
    newhead=newtail=NULL;
    while(n1&&n2)
    {
        if(n1->valval)
        {
            if(newhead==NULL)
            {
                // 如果新链表头为空,则将当前节点设为新链表头和新链表尾
                newhead=newtail=n1;
            }
            else
            {
                // 如果新链表头不为空,则将当前节点接在新链表尾后,并更新新链表尾
                newtail->next=n1;
                newtail=newtail->next;
            }
            n1=n1->next;
        }
        else
        {
            if(newhead==NULL)
            {
                // 如果新链表头为空,则将当前节点设为新链表头和新链表尾
                newhead=newtail=n2;
            }
            else
            {
                // 如果新链表头不为空,则将当前节点接在新链表尾后,并更新新链表尾
                newtail->next=n2;
                newtail=newtail->next;
            }
            n2=n2->next;
        }
    }
    if(n1)
    {
        // 如果list1还有剩余节点,则将剩余节点接在新链表尾后,并更新新链表尾
        newtail->next=n1;
        newtail=newtail->next;
    }
    if(n2)
    {
        // 如果list2还有剩余节点,则将剩余节点接在新链表尾后,并更新新链表尾
        newtail->next=n2;
        newtail=newtail->next;
    }
    return newhead;
}


 

 

问题5:环形链表的约瑟夫问题

题目链接:环形链表的约瑟夫问题_牛客题霸_牛客网

c语言:链表经典算法oj题_第5张图片

方法:环形链表

创建一个环形链表,每个人对应一个节点,将对应的离开人数的节点释放掉,并且改边释放节点前后指针的指向,直到剩一人为止

typedef struct ListNode ListNode; // 定义一个 ListNode 结构体的别名为 ListNode
ListNode* BuyNode(int x) // 定义一个函数 BuyNode,用于创建一个新的节点并返回指向该节点的指针
{
    ListNode*newnode=(ListNode*)malloc(sizeof(ListNode)); // 分配内存空间
    newnode->val=x; // 设置节点的值为 x
    newnode->next=NULL; // 下一个节点指针为空
    return newnode; // 返回指向新节点的指针
}
// 创建不带头环形链表
ListNode*ctreatelist(int n) 
{
    ListNode*phead=BuyNode(1); // 创建头节点
    ListNode*ptail=phead; // 尾节点指向头节点
    for(int i=2;i<=n;i++) // 循环创建 n 个节点
    {
        ptail->next=BuyNode(i); // 创建新节点并连接到尾节点的下一个
        ptail=ptail->next; // 尾节点指向新创建的节点
    }
    ptail->next=phead; // 尾节点指向头节点,形成环形链表
    return phead; // 返回头节点指针
}
// 约瑟夫环问题
int ysf(int n, int m ) {
    ListNode*head=ctreatelist(n); // 创建包含 n 个节点的环形链表
    ListNode*pcur=head; // 当前节点指针指向头节点
    ListNode*prev=NULL; // 前一个节点指针初始化为空
    int count=1; // 计数器初始化为 1
    while(pcur->next!=pcur) // 当链表中还有多于一个节点时循环
    {
        if(count==m) // 当计数器等于 m 时
        {
            // 删除当前节点
            prev->next=pcur->next; // 前一个节点的指针指向当前节点的下一个节点
            free(pcur); // 释放当前节点的内存空间
            pcur=prev->next; // 当前节点指针指向下一个节点
            count=1; // 计数器重置为 1
        }
        else
        {
            prev=pcur; // 前一个节点指针指向当前节点
            pcur=pcur->next; // 当前节点指针指向下一个节点
            count++; // 计数器加 1
        } 
    }
    return pcur->val; // 返回最后剩下的节点的值
}

你可能感兴趣的:(数据结构,c语言,链表,算法)