【C算法】链表算法

移除链表元素

链接: 移除链表元素

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val) 
{
   //设置俩个指针
   //prev用来记录val前面的指针
   //假设将prev的指向head的前面,即为NULL
   struct ListNode* prev = NULL;
   //cur用来判断,cur指向链表第一个
   struct ListNode* cur = head;
   //利用prev和cur进行循环
   //当cur为NULL停止
   while(cur != NULL)
    {
      
        if(cur->val != val)
        {
            //cur的值不等于val时
            //prev向后移动一步
            //cur向后移动一步
            prev = cur;
            cur = cur->next;
        }
        else
        {
            //判断如果一个值为val时,此时prev任然为NULL;
            //需要将这种cur向后移
            if(prev == NULL)
            {
                //将head指向下一个
                head = cur->next;
                //释放cur
                free(cur);
                //cur重新指向head的值
                cur = head;
            }
            else
            {
                //cur的值等于val时
                //将prev指向的地址向后移动一步
                prev->next = cur->next;
                //释放cur所在的内存
                free(cur);
                //将粗人指向新的prev后面的位置
                cur = prev->next;
            }
              
        }
        
    }
    return head;
}

链表的中间结点

链接: 链表的中间结点

思路:使用快慢指针进行解答
1.定义一个快指针和慢指针均指向头指针
2.快指针一次走俩步,慢指针一次走一步
3.当快指针为空指针或者快指针的下一个指针为空时结束

在这里插入图片描述

代码详解:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head) 
{
    //定义一个快指针,一次走俩格
    struct ListNode* fast = head;
    //定义一个慢指针,一次走一格
    struct ListNode* slow = head;
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

返回倒数第k个结点

链接: 返回倒数第k个结点

在这里插入图片描述

思路:使用先后指针解答
1.定义一个先走指针fast和慢走指针slow
2.先走指针要比慢走指针快k步
3.然后俩个指针同时进行移动
4.当先走指针遇到NULL时停止

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


int kthToLast(struct ListNode* head, int k)
{
    //定义一个先走指针,
    struct ListNode* fast = head;
    //定义一个慢走指针
    struct ListNode* slow = head;
    //先走指针比慢走指针快k步
    while(k--)
    {
        fast = fast->next;
    }
    //俩个指针一起走
    while(fast != NULL)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow->val;
}

合并俩个有序链表

链接:合并俩个有序链表
在这里插入图片描述

思路:
1.定义cur1指向list1的头结点,定义cur2指向list2的头结点,定义head和end指向空
2.cur1用来遍历list1,cur2用来遍历list2,head用来记录合并后的头结点,end用来记录合并后的尾结点,以确保可以向后添加结点
3.判断是否有空,但凡有一个为空,就可以返回另外一个;如果俩个都不为空,需要设置合并后的头结点head
4.当俩个都不为空,进入循环,向end后面接结点
5.当俩个中间有一个为空时,可以只在将另一个接在end后面

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
	//设置四个结点
    struct ListNode* cur1 = list1;
    struct ListNode* cur2 = list2;
    struct ListNode* head = NULL;
    struct ListNode* end = NULL;
    //判断如何都不为空
    if (cur1 && cur2)
    {
    //将合并后头结点head指向小值
        if (cur1->val < cur2->val)
        {
            head = end = cur1;
            cur1 = cur1->next;
        }
        else
        {
            head = end = cur2;
            cur2 = cur2->next;
        }
    }
    //cur1与cur2都不为空所以不需要判断else,如果没有else,设置完头结点head后,有一个可能为空,导致返回。
    else if (cur1 == NULL)//cur1为空,返回cur2
    {
        return cur2;
    }
    else if (cur2 == NULL)//cur2为空。返回cur1
    {
        return cur1;
    }
    //俩个都不为空进行插入链表
    while (cur1 && cur2)
    {
    //每次插入都需要,将cur和end向后移动
        if (cur1->val <= cur2->val)
        {
            end->next = cur1;
            cur1 = cur1->next;
            end = end->next;
        }
        else
        {
            end->next = cur2;
            cur2 = cur2->next;
            end = end->next;
        }
    }
    //如果其中一个为空,可以直接将另一个后面的全部接在end后面
    if (cur1 == NULL)
    {
        end->next = cur2;
    }
    if (cur2 == NULL)
    {
        end->next = cur1;
    }
    return head;
}

链表分割

链接:链表分割

在这里插入图片描述

思路:
1.首先需要创建俩个哨兵结点来将大值结点与小结点分割开
2.使用四个指针指向俩个哨兵结点,begin1、begin2、end1、end2
3.begin1与begin2保留俩个哨兵结点的位置,end1与end2接后面的结点
4.然后将俩个哨兵结点相连,注意需要释放空间

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) 
    {
        //创建俩个哨兵结点
        //使用begin1与end1指向第一个哨兵
        //使用begin2与end2指向第二个哨兵
        struct ListNode* begin1;
        struct ListNode* begin2;
        struct ListNode* end1;
        struct ListNode* end2;
        begin1 = (struct ListNode*)malloc(sizeof(struct ListNode));
        begin2 = (struct ListNode*)malloc(sizeof(struct ListNode));
        if(begin1 == NULL || begin2 == NULL)
        {
            perror("malloc fail");
            return NULL;
        }
        begin1->next = NULL;
        begin2->next = NULL;
        end1 = begin1;
        end2 = begin2;
        //将小于x的结点接在begin1后面
        //将大于等于x的结点接在begin2后面
        while(pHead != NULL)
        {
            if(pHead->val < x)
            {
                end1->next = pHead;
                end1 = end1->next;
            }
            else
            {
                end2->next = pHead;
                end2 = end2->next;
            }
            pHead = pHead->next;
        }
        //将end1与end2后面置空
        end1->next = NULL;
        end2->next = NULL;
        //将大于等于x的结点接在小于x的结点后面
        end1->next = begin2->next;
        //将小于x的第一个结点设置为头结点
        pHead = begin1->next;
        //注意需要释放malloc创建的堆区已经野指针问题
        free(begin1);
        free(begin2);
        begin1 = begin2 = end1 = end2 = NULL;

        return pHead;
    }
};

相交链表

链接: 相交链表
在这里插入图片描述

思路:
1.定义俩个指向链表的指针和俩个计算结点个数(长度)的变量
2.求出俩个链表有几个结点,即链表的长度
3.如果最后一个结点处,二者并没有相交,则返回NULL
4.将俩个链表的结点个数(长度)相减,让结点个数(长度)多(长)的先走相减的个数。
5.最后俩条链表同时走,遇到相同结点时结束

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    //设置L1和L2计算俩条链的长度
    int L1 = 1, L2 = 1;
    //设置俩个指针指向俩条链的头结点
    struct ListNode* cur1 = headA;
    struct ListNode* cur2 = headB;
    //计算L1的长度
    while(cur1->next != NULL)
    {
        cur1 = cur1->next;
        ++L1;
    }
    //计算L2的长度
    while(cur2->next != NULL)
    {
        cur2 = cur2->next;
        ++L2;
    }
    //判断如果俩个直接的最好交点不在一起则直接返回NULL
    if(cur1 != cur2)
    {
        return NULL;
    }
    //计算链的长度差
    int L = L1 - L2;
    //将移动的指针重新指向头结点
    cur1 = headA;
    cur2 = headB;
    //让长度较长的指针先走L步
    if(L > 0)
    {
        while(L--)
        {
            cur1 = cur1->next;
        }
    }
    else
    {
        while(L++)
        {
            cur2 = cur2->next;
        }
    }
    //俩个指针同时走,发现相同时停止
    while(cur1 != cur2)
    {
        cur1 = cur1->next;
        cur2 = cur2->next;
    }
    return cur1;
}

环形链表

链接: 环形链表
在这里插入图片描述

思路:
1.判断是否存在空结点和只有一个结点的情况
2.定义一个快结点和一个慢结点
3.快结点一次走俩步,慢结点一次走一步
4.当二者相遇时结束

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) 
{
    //判断是否存在空链表或者链表中只存在一个结点
    if(head == NULL || head->next == NULL)
    {
        return false;
    }
    //定义一个快结点和慢结点
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    //快结点一次走俩步
    //慢结点一次走一步
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
        //相遇时结束
        if(fast == slow)
        {
            return true;
        }
    }
    return false;
}

链表的回文结构

链接: 链表的回文结构

在这里插入图片描述

思路:
1.判断当存在空链表或者当个链表时返回true
2.设置快慢指针求得中间结点
3.使用三个指针翻转后半段链表
4.使用一前一后俩个指针判断是否为回文结构

难点:使用三个指针翻转链表时,循环停止的条件为中间的指针为空,此时需要第三个结点在循环内初始化,这样才能保证后面每一个链表都能翻转过来,并且当第三个结点为空时,不会执行next

  • 代码实现:
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) 
    {
        //链表为空或者链表只有一个返回true
        if(A == NULL || A->next == NULL)
        {
            return true;
        }
        //设置快慢指针
        //快指针一次走俩步
        //慢指针一次走一步
        struct ListNode* fast = A;
        struct ListNode* slow = A;
        //寻找中间结点
        while(fast != NULL && fast->next != NULL)
        {
            fast = fast->next->next;
            slow = slow->next;
        }
        //slow此时所在位置为中间结点
        //从中间结点往后开始翻转链表
        struct ListNode* cur = slow->next;
        while(cur != NULL)
        {
            struct ListNode* cur_next = cur->next;
            cur->next = slow;
            slow = cur;
            cur = cur_next;
        }
        //设置一个头结点和尾结点
        struct ListNode* tail = slow;
        struct ListNode* head = A;
        //一前一后开始比较
        //比较正确,比较下一个
        //比较错误,返回错误
        while( head != tail)//奇数时二者相遇
        {
            if(head->val != tail->val)
            {
                return false;
            }
            if(head->next == tail)
            {
                //偶数时head的下一个是tail
                return true;
            }
            head = head->next;
            tail = tail->next;
        }
        return true;
    }
};
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RR调度算法(Round-Robin Scheduling Algorithm)是一种常用的调度算法,它按照时间片轮转的方式为每个进程分配CPU时间。下面是一个使用C语言实现的简单的RR调度算法的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义进程结构体 typedef struct Process { int pid; // 进程ID int burstTime; // 执行时间 int remainingTime; // 剩余执行时间 } Process; // 定义链表节点结构体 typedef struct Node { Process process; struct Node* next; } Node; // 创建新的链表节点 Node* createNode(Process process) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->process = process; newNode->next = NULL; return newNode; } // 在链表尾部插入节点 void insertAtEnd(Node** head, Process process) { Node* newNode = createNode(process); if (*head == NULL) { *head = newNode; } else { Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } } // 执行RR调度算法 void runRR(Node* head, int timeSlice) { Node* current = head; while (current != NULL) { if (current->process.remainingTime > 0) { if (current->process.remainingTime > timeSlice) { printf("Process %d is running for time slice %d\n", current->process.pid, timeSlice); current->process.remainingTime -= timeSlice; } else { printf("Process %d is running for remaining time %d\n", current->process.pid, current->process.remainingTime); current->process.remainingTime = 0; } } current = current->next; } } int main() { // 创建进程链表 Node* head = NULL; insertAtEnd(&head, (Process){1, 10, 10}); insertAtEnd(&head, (Process){2, 5, 5}); insertAtEnd(&head, (Process){3, 8, 8}); // 执行RR调度算法,时间片为2 runRR(head, 2); return 0; } ``` 上述代码中,首先定义了进程结构体和链表节点结构体。然后,通过`createNode`函数创建新的链表节点,`insertAtEnd`函数将节点插入链表尾部。最后,`runRR`函数执行RR调度算法,遍历链表中的每个进程,并根据时间片的大小进行调度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值