作业调度和进程调度的简单模拟(C语言)

news/2024/9/9 10:15:32/

一、作业调度

1.题目描述

假定要在一台处理器上执行下表所示的作业,且假定这些作业在时刻 0 以 1、2、3、4、5 的顺序到达。说明分别使用 FCFSRR(时间片为 1)、SJF非剥夺式优先级调度算法时这些作业的执行情况(优先级从 1 到 5 依次降低)。针对上述每个调度算法,给出平均周转时间平均带权周转时间

作业执行时间优先级
1103
211
323
414
552

注:题目来自王道《操作系统考研复习指导》

调度算法{FirstComeFirstServed:作业、进程调度,非抢占式,不会导致饥饿,有利于长作业和CPU繁忙型作业ShortJob/ProcessFirst:作业、进程调度,非抢占式,会导致饥饿,有利于短作业ShortestRemainingTimeFirst:作业、进程调度,抢占式,会导致饥饿,有利于短作业HighestResponseRatioNext:作业、进程调度,非抢占式,不会导致饥饿,响应比=等待时间+要求服务时间要求服务时间RoundRobin:仅用于进程调度(只有进程才能分配时间片),抢占式,不会导致饥饿PrioritySchedulingAlgorithm:作业、进程调度,会导致饥饿,有利于系统、I/O和前台等高优先级进程MultilevedFeedbackQueue:仅用于进程调度,抢占式,会导致饥饿调度算法\begin{cases} \rm First\ Come\ First\ Served:作业、进程调度,非抢占式,不会导致饥饿,有利于长作业和CPU繁忙型作业\\ \rm Short\ Job/Process\ First:作业、进程调度,非抢占式,会导致饥饿,有利于短作业\\ \rm Shortest\ Remaining\ Time\ First:作业、进程调度,抢占式,会导致饥饿,有利于短作业\\ \rm Highest\ Response\ Ratio\ Next:作业、进程调度,非抢占式,不会导致饥饿,响应比=\frac{等待时间+要求服务时间}{要求服务时间}\\ \rm Round\ Robin:仅用于进程调度(只有进程才能分配时间片),抢占式,不会导致饥饿\\ \rm Priority\ Scheduling\ Algorithm:作业、进程调度,会导致饥饿,有利于系统、I/O和前台等高优先级进程\\ \rm Multileved\ Feedback\ Queue:仅用于进程调度,抢占式,会导致饥饿 \end{cases} 调度算法First Come First Served:作业、进程调度,非抢占式,不会导致饥饿,有利于长作业和CPU繁忙型作业Short Job/Process First:作业、进程调度,非抢占式,会导致饥饿,有利于短作业Shortest Remaining Time First:作业、进程调度,抢占式,会导致饥饿,有利于短作业Highest Response Ratio Next:作业、进程调度,非抢占式,不会导致饥饿,响应比=要求服务时间等待时间+要求服务时间Round Robin:仅用于进程调度(只有进程才能分配时间片),抢占式,不会导致饥饿Priority Scheduling Algorithm:作业、进程调度,会导致饥饿,有利于系统、I/O和前台等高优先级进程Multileved Feedback Queue:仅用于进程调度,抢占式,会导致饥饿

2.代码实现

通过代码对四种调度算法进行简单模拟,并非对调度算法的实现,同时输出每次的调度信息,计算相关周转参数。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>#define JOB_NUM 5 // 作业数量/* 作业结构体的定义 */
typedef struct Job {char name[3]; // 作业名称int priority; // 作业优先级int arr_order; // 到达次序int cos_time; // 作业执行时间int rem_time; // 作业剩余时间
} Job;/* 时间片轮转队列节点定义 */
typedef struct QueueNode {Job data; // 数据域struct QueueNode *next; // 指针域
} QueueNode;/* 时间片轮转队列定义 */
typedef struct Queue {QueueNode *head, *tail; // 队列指针
} Queue;/* 初始化单个作业的信息 */
void jobInit(Job *job, char *name, int arr_order, int cos_time, int priority);/* 初始化作业列表中的作业信息 */
void jobListInit(Job *job_list);/* 时间片轮转队列初始化 */
void queueInit(Queue *queue);/* 时间片轮转队列销毁 */
void queueDestroy(Queue *queue);/* 时间片轮转队列判空 */
bool queueIsEmpty(Queue queue);/* 时间片轮转队列入队 */
void queueEmplace(Queue *queue, Job job);/* 时间片轮转队列出队 */
Job queuePop(Queue *queue);/* 先来先服务 */
void FCFS(Job *job_list);/* 时间片轮转调度算法 */
void RR(Job *job_list);/* 短作业优先 */
void SJF(Job *job_list);/* 优先级调度 */
void PSA(Job *job_list);int main(int argc, char *argv[]) {if (argc == 1) {printf("请输入使用的调度算法!\n");return 0;}Job job_list[JOB_NUM];jobListInit(job_list);if (strcmp(argv[1], "FCFS") == 0) {FCFS(job_list);} else if (strcmp(argv[1], "RR") == 0) {RR(job_list);} else if (strcmp(argv[1], "SJF") == 0) {SJF(job_list);} else {PSA(job_list);}return 0;
}void jobInit(Job *job, char *name, int arr_order, int cos_time, int priority) {strcpy(job->name, name);job->priority = priority;job->arr_order = arr_order;job->cos_time = cos_time;job->rem_time = cos_time;
}void jobListInit(Job *job_list) {jobInit(job_list + 0, "J1", 1, 10, 3);jobInit(job_list + 1, "J2", 2, 1, 1);jobInit(job_list + 2, "J3", 3, 2, 3);jobInit(job_list + 3, "J4", 4, 1, 4);jobInit(job_list + 4, "J5", 5, 5, 2);
}void queueInit(Queue *queue) {queue->head = queue->tail = (QueueNode *) malloc(sizeof(QueueNode));queue->head->next = NULL;
}void queueDestroy(Queue *queue) {QueueNode *cur = queue->head;while (cur) {QueueNode *tmp = cur;free(tmp);cur = cur->next;}
}bool queueIsEmpty(Queue queue) {return (queue.head == queue.tail) ? true : false;
}void queueEmplace(Queue *queue, Job job) {QueueNode *new_node = (QueueNode *) malloc(sizeof(QueueNode));new_node->data = job;new_node->next = NULL;queue->tail->next = new_node;queue->tail = queue->tail->next;
}Job queuePop(Queue *queue) {if (queue->tail == queue->head->next) { // 本次出队会导致队空queue->tail = queue->head;}Job job = queue->head->next->data;QueueNode *tmp = queue->head->next;queue->head->next = tmp->next;free(tmp);return job;
}void FCFS(Job *job_list) {/* 根据到达次序对作业进行排序 */for (int i = 0; i < JOB_NUM - 1; i++) {for (int j = 0; j < JOB_NUM - 1 - i; j++) {if (job_list[j].arr_order > job_list[j + 1].arr_order) {Job tmp = job_list[j];job_list[j] = job_list[j + 1];job_list[j + 1] = tmp;}}}double turnaround_time_total = 0; // 周转时间之和double weighted_turnaround_time_total = 0; // 带权周转时间之和int current_time = 0; // 当前时刻for (int i = 0; i < JOB_NUM; i++) {printf("第%d次调度:\n当前执行作业:%s\n等待作业队列:", i + 1, job_list[i].name);for (int j = i + 1; j < JOB_NUM; j++) {printf("%s%c", job_list[j].name, (j == JOB_NUM - 1) ? 0 : 32);}printf("\n\n");current_time += job_list[i].cos_time; // 更新时刻turnaround_time_total += current_time; // 累加周转时间weighted_turnaround_time_total += current_time * 1.0 / job_list[i].cos_time; // 累加带权周转时间}printf("平均周转时间:%.2f\n", turnaround_time_total / JOB_NUM);printf("平均带权周转时间:%.2f\n", weighted_turnaround_time_total / JOB_NUM);
}void RR(Job *job_list) {/* 根据到达次序对作业进行排序 */for (int i = 0; i < JOB_NUM - 1; i++) {for (int j = 0; j < JOB_NUM - 1 - i; j++) {if (job_list[j].arr_order > job_list[j + 1].arr_order) {Job tmp = job_list[j];job_list[j] = job_list[j + 1];job_list[j + 1] = tmp;}}}Queue queue;queueInit(&queue);for (int i = 0; i < JOB_NUM; i++) {queueEmplace(&queue, job_list[i]);}double turnaround_time_total = 0; // 周转时间之和double weighted_turnaround_time_total = 0; // 带权周转时间之和int current_time = 0; // 当前时刻int count = 1; // 调度次数计数器while (!queueIsEmpty(queue)) {/* 轮转队列中仅剩最后一个作业 进行最后一次调度 */if (queue.head->next == queue.tail) {printf("第%d次调度:\n", count++);Job now_job = queuePop(&queue);printf("当前执行作业:%s\n", now_job.name);printf("等待作业队列:\n\n");turnaround_time_total += current_time + now_job.rem_time; // 累加周转时间weighted_turnaround_time_total += (current_time + now_job.rem_time) * 1.0 / now_job.cos_time; // 累加带权周转时间break;}printf("第%d次调度:\n", count++);Job now_job = queuePop(&queue);printf("当前执行作业:%s\n", now_job.name);now_job.rem_time -= 1;current_time++;printf("等待作业队列:");for (QueueNode *cur = queue.head->next; cur != NULL; cur = cur->next) {printf("%s%c", cur->data.name, (cur->next == NULL) ? 0 : 32);}printf("\n\n");if (now_job.rem_time > 0) {queueEmplace(&queue, now_job);} else {turnaround_time_total += current_time; // 累加周转时间weighted_turnaround_time_total += current_time * 1.0 / now_job.cos_time; // 累加带权周转时间}}queueDestroy(&queue);printf("平均周转时间:%.2f\n", turnaround_time_total / JOB_NUM);printf("平均带权周转时间:%.2f\n", weighted_turnaround_time_total / JOB_NUM);
}void SJF(Job *job_list) {/* 根据消耗时间对作业进行排序 优先考虑稳定排序 */for (int i = 0; i < JOB_NUM - 1; i++) {for (int j = 0; j < JOB_NUM - 1 - i; j++) {if (job_list[j].cos_time > job_list[j + 1].cos_time) {Job tmp = job_list[j];job_list[j] = job_list[j + 1];job_list[j + 1] = tmp;}}}double turnaround_time_total = 0; // 周转时间之和double weighted_turnaround_time_total = 0; // 带权周转时间之和int current_time = 0; // 当前时刻for (int i = 0; i < JOB_NUM; i++) {printf("第%d次调度:\n当前执行作业:%s\n等待作业队列:", i + 1, job_list[i].name);for (int j = i + 1; j < JOB_NUM; j++) {printf("%s%c", job_list[j].name, (j == JOB_NUM - 1) ? 0 : 32);}printf("\n\n");current_time += job_list[i].cos_time; // 更新时刻turnaround_time_total += current_time; // 累加周转时间weighted_turnaround_time_total += current_time * 1.0 / job_list[i].cos_time; // 累加带权周转时间}printf("平均周转时间:%.2f\n", turnaround_time_total / JOB_NUM);printf("平均带权周转时间:%.2f\n", weighted_turnaround_time_total / JOB_NUM);
}void PSA(Job *job_list) {/* 根据优先级对作业进行排序 优先考虑稳定排序 */for (int i = 0; i < JOB_NUM - 1; i++) {for (int j = 0; j < JOB_NUM - 1 - i; j++) {if (job_list[j].priority > job_list[j + 1].priority) {Job tmp = job_list[j];job_list[j] = job_list[j + 1];job_list[j + 1] = tmp;}}}double turnaround_time_total = 0; // 周转时间之和double weighted_turnaround_time_total = 0; // 带权周转时间之和int current_time = 0; // 当前时刻for (int i = 0; i < JOB_NUM; i++) {printf("第%d次调度:\n当前执行作业:%s\n等待作业队列:", i + 1, job_list[i].name);for (int j = i + 1; j < JOB_NUM; j++) {printf("%s%c", job_list[j].name, (j == JOB_NUM - 1) ? 0 : 32);}printf("\n\n");current_time += job_list[i].cos_time; // 更新时刻turnaround_time_total += current_time; // 累加周转时间weighted_turnaround_time_total += current_time * 1.0 / job_list[i].cos_time; // 累加带权周转时间}printf("平均周转时间:%.2f\n", turnaround_time_total / JOB_NUM);printf("平均带权周转时间:%.2f\n", weighted_turnaround_time_total / JOB_NUM);
}

运行结果示例如下:

atreus@MacBook-Pro % clang 1.1.c -o exe.out
atreus@MacBook-Pro % ./exe.out FCFS
第1次调度:
当前执行作业:J1
等待作业队列:J2 J3 J4 J5第2次调度:
当前执行作业:J2
等待作业队列:J3 J4 J5第3次调度:
当前执行作业:J3
等待作业队列:J4 J5第4次调度:
当前执行作业:J4
等待作业队列:J5第5次调度:
当前执行作业:J5
等待作业队列:平均周转时间:13.40
平均带权周转时间:7.26
atreus@MacBook-Pro % ./exe.out RR  
第1次调度:
当前执行作业:J1
等待作业队列:J2 J3 J4 J5第2次调度:
当前执行作业:J2
等待作业队列:J3 J4 J5 J1第3次调度:
当前执行作业:J3
等待作业队列:J4 J5 J1第4次调度:
当前执行作业:J4
等待作业队列:J5 J1 J3第5次调度:
当前执行作业:J5
等待作业队列:J1 J3第6次调度:
当前执行作业:J1
等待作业队列:J3 J5第7次调度:
当前执行作业:J3
等待作业队列:J5 J1第8次调度:
当前执行作业:J5
等待作业队列:J1第9次调度:
当前执行作业:J1
等待作业队列:J5第10次调度:
当前执行作业:J5
等待作业队列:J1第11次调度:
当前执行作业:J1
等待作业队列:J5第12次调度:
当前执行作业:J5
等待作业队列:J1第13次调度:
当前执行作业:J1
等待作业队列:J5第14次调度:
当前执行作业:J5
等待作业队列:J1第15次调度:
当前执行作业:J1
等待作业队列:平均周转时间:9.20
平均带权周转时间:2.84
atreus@MacBook-Pro % ./exe.out SJF
第1次调度:
当前执行作业:J2
等待作业队列:J4 J3 J5 J1第2次调度:
当前执行作业:J4
等待作业队列:J3 J5 J1第3次调度:
当前执行作业:J3
等待作业队列:J5 J1第4次调度:
当前执行作业:J5
等待作业队列:J1第5次调度:
当前执行作业:J1
等待作业队列:平均周转时间:7.00
平均带权周转时间:1.74
atreus@MacBook-Pro % ./exe.out PSA
第1次调度:
当前执行作业:J2
等待作业队列:J5 J1 J3 J4第2次调度:
当前执行作业:J5
等待作业队列:J1 J3 J4第3次调度:
当前执行作业:J1
等待作业队列:J3 J4第4次调度:
当前执行作业:J3
等待作业队列:J4第5次调度:
当前执行作业:J4
等待作业队列:平均周转时间:12.00
平均带权周转时间:6.36
atreus@MacBook-Pro % 

二、作业调度进程调度混合

1.题目描述

有一个两道批处理系统,它只有一个 CPU(一次只能处理一个进程),作业调度算法采用短作业优先调度进程调度算法采用抢占式优先级调度(优先数越小、优先级越高)。假设有四个作业J1、J2、J3、J4,其运行情况如下表所示,请输出作业调度和进程调度状态并计算平均周转时间。

作业名到达时间运行时间优先数
J10405
J220303
J330504
J450206

2.代码实现

#include <stdio.h>
#include <stdlib.h>#define N 4enum job_state {WAIT = 0, // 作业在外存等待调度READY = 1, // 已经为作业分配线程 处于就绪态 由于SJF为非抢占 作业不会被换出内存RUN = 2, // 运行态 可能会被高优先级进程抢占FINISH = 3 // 作业已经完成
};/* 作业结构体的定义 */
typedef struct Job {char name[3]; // 作业名称int priority; // 作业优先级int arr_time; // 作业到达时间int cos_time; // 作业执行时间int rem_time; // 作业剩余时间enum job_state state; // 作业状态
} Job;Job job_list[N] = {{"J1", 5, 0,  40, 40, WAIT},{"J2", 3, 20, 30, 30, WAIT},{"J3", 4, 30, 50, 50, WAIT},{"J4", 6, 50, 20, 20, WAIT}};/*** 作业调度 采用 短作业优先 调度算法* 进程调度 采用 抢占式优先级 调度算法*/
int main() {int mem_space = 2; // 内存中还可存放的作业数int task_num = N; // 待处理作业总数int finish_count = 0; // 记录已经完成任务的作业数int cur_time = 0; // 实时时间int sum_time = 0; // 周转时间和/* 通过while(1)循环模拟系统执行 循环周期为1个单位时间 当所有作业完成时退出 */while (1) {/* 作业调度 *//* 按照消耗时间从小到大对任务进行排序 优先调度短作业 */for (int i = 0; i < task_num; i++) {for (int j = 0; j < task_num - i - 1; j++) {if (job_list[j].cos_time > job_list[j + 1].cos_time) {Job tmp = job_list[j];job_list[j] = job_list[j + 1];job_list[j + 1] = tmp;}}}/* 选取小于等于mem_space个作业放入内存 并将其标记为READY状态 *//* 由于已经提前进行排序 所以遍历时只要满足arr_time <= cur_time就可以调入内存 */int tmp_count = mem_space;for (int i = 0; i < tmp_count; i++) {for (int j = 0; j < task_num; j++) {if (job_list[j].arr_time <= cur_time && job_list[j].state == WAIT) { // 作业已经到达且在外存等待printf("作业调度:%d-%s\n", cur_time, job_list[j].name);job_list[j].state = READY;mem_space--;break;}}}/* 进程调度 */for (int i = 0; i < task_num; i++) {for (int j = 0; j < task_num - i - 1; j++) {if (job_list[j].priority > job_list[j + 1].priority) {Job tmp = job_list[j];job_list[j] = job_list[j + 1];job_list[j + 1] = tmp;}}}/* 由于已经提前进行排序 所以遍历时只要满足状态为READY或RUN就可以调入CPU执行 */int add_time = INT32_MAX; // 本轮执行需要消耗的时间for (int i = 0; i < task_num; i++) {if (job_list[i].state == READY) { // 从内存调入CPU执行cur_time++;/* 检查当前进程放入CPU是否会抢占其他进程 */for (int j = i + 1; j < task_num; j++) {if (job_list[j].state == RUN) {job_list[j].state = READY;break;}}job_list[i].state = RUN;if (--job_list[i].rem_time == 0) {job_list[i].state = FINISH;finish_count++;sum_time += (cur_time - job_list[i].arr_time);mem_space++;}printf("进程调度:%d-%s\n", cur_time, job_list[i].name);break;} else if (job_list[i].state == RUN) { // 在CPU上维持执行cur_time++;if (--job_list[i].rem_time == 0) {job_list[i].state = FINISH;finish_count++;sum_time += (cur_time - job_list[i].arr_time);mem_space++;}break;}}if (finish_count == 4) {break;}}printf("平均周转时间为:%.2f\n", sum_time * 1.0 / task_num);
}

运行结果示例如下:

atreus@MacBook-Pro % clang 1.2.c -o exe.out
atreus@MacBook-Pro % ./exe.out 
作业调度:0-J1
进程调度:1-J1
作业调度:20-J2
进程调度:21-J2
作业调度:50-J4
进程调度:51-J1
作业调度:70-J3
进程调度:71-J3
进程调度:121-J4
平均周转时间为:70.00
atreus@MacBook-Pro % 

http://www.ppmy.cn/news/30030.html

相关文章

dev GridControl 按条件纵向合并单元格

dev GridControl 按条件纵向合并单元格 gridView5.OptionsView.AllowCellMerge true; gridView5.CellMerge gridView5_CellMerge; //自定义合并单元格监听事件void gridView5_CellMerge(object sender, DevExpress.XtraGrid.Views.Grid.CellMergeEventArgs e){int rowHandle1…

Linux系统GPIO应用编程

目录应用层如何操控GPIOGPIO 应用编程之输出GPIO 应用编程之输入GPIO 应用编程之中断在开发板上测试GPIO 输出测试GPIO 输入测试GPIO 中断测试本章介绍应用层如何控制GPIO&#xff0c;譬如控制GPIO 输出高电平、或输出低电平。应用层如何操控GPIO 与LED 设备一样&#xff0c;G…

Git标签与版本发布

1. 什么是git标签 标签&#xff0c;就类似我们阅读时的书签&#xff0c;可以很轻易找到自己阅读到了哪里。 对于git来说&#xff0c;在使用git对项目进行版本管理的时候&#xff0c;当我们的项目开发到一定的阶段&#xff0c;需要发布一个版本。这时&#xff0c;我们就可以对…

《C++ Primer Plus》第18章:探讨 C++ 新标准(9)

编程练习 下面是一个简短程序的一部分&#xff1a; int main() {using namespace std;// list of double deduced from list contentsauto q average_list ({15.4, 10.7, 9.0});cout << q << endl;// list of int deduced from list contentscout << averag…

SQL中字符串截取函数 SUBSTRING

1、left&#xff08;name,4&#xff09;截取左边的4个字符 列&#xff1a; SELECT LEFT(201809,4) 年 结果&#xff1a;2018 2、right&#xff08;name,2&#xff09;截取右边的2个字符 SELECT RIGHT(201809,2) 月份 结果&#xff1a;09 3、SUBSTRING(name,5,3) 截取nam…

初识数据结构——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰进入一个全新的内容的学习&#xff0c;就是算法和数据结构啦&#xff0c;话不多说&#xff0c;让我们进入数据结构的世界吧 什么是数据结构&#xff1f; 什么是算法&#xff1f; 数据结构和算法的重要性 如何学好数据结构和算…

【python中的列表和元组】

文章目录前言一、列表及其使用1.列表的特点2. 列表的使用方法二、元组及其特点1.元组的类型是tuple1.元组的查找操作2. 计算元组某个元素出现的次数3.统计元组内元素的个数总结前言 本文着重介绍python中的列表和元组以及列表和元组之间的区别 一、列表及其使用 1.列表的特点…

重构·改善既有代码的设计.01

前言近期在看Martin Fowler著作的《重构.改善既有代码的设计》这本书&#xff0c;这是一本经典著作。书本封面誉为软件开发的不朽经典。书中从一个简单的案例揭示了重构的过程以及最佳实践。同时给出了重构原则&#xff0c;何时重构&#xff0c;以及重构的手法。用来改善既有代…

【微信小程序】-- 案例 - 本地生活(二十)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

【springcloud 微服务】Spring Cloud Alibaba 整合Nacos实战

目录 一、前言 二、常用服务注册中心介绍 2.1 dubbo服务注册示意图 2.2 常用注册中心对比 三、nacos介绍 3.1 什么是nacos 3.2 nacos 特点 3.3 nacos生态链地图 四、nacos部署 4.1 下载安装包 4.2 修改脚本启动模式 4.3 启动nacos 服务 五、Spring Cloud Alibaba…

刷题记录:CF1285D Dr. Evil Underscores 区间异或使序列最大值最小

传送门:CF 题目描述: 有一个长度为 n(1≤n≤105)n\ (1\leq n\leq 10^5)n (1≤n≤105) 的整数序列 a1,⋯,an(0≤ai≤230−1)a_1,\cdots,a_n\ \ (0\leq a_i\leq 2^{30}-1)a1​,⋯,an​ (0≤ai​≤230−1)&#xff0c;你需要找到一个非负整数 XXX 使得 max⁡(ai⊕X)\max(a_i\op…

【python】JSON数据类型与Python数据类型之间的转化

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录JSON格式文件JSON格式序列化与反序列化作用JSON常用数据结构键值对的集合值的有序列表JSON数据类型与Python数据类型之间的转化JSON格式和python的区别读写json文件dump 把python 写到json文件load 把json写…

C语言刷题(4)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容又到了我们的复习啦&#xff0c;那么还是刷题噢&#xff0c;话不多说&#xff0c;让我们进入C语言的世界吧 BC55 简单计算器 BC56 线段图案 BC57 正方形图案 BC58 直角三角形图案 BC59 翻转直角三角形图案 BC60 带空格…

蚁群算法优化问题

%%%%%%%%%%%%蚁群算法解决 TSP 问题%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%初始化%%%%%%%%%%%%%%%%%%% clear all; %清除所有变量 close all; %清图 clc; %清屏 m 50; %蚂蚁个数 Alpha 1; %信息素重要程度参数 Beta 5; %启发式因子重要程度参数 Rho 0.1; %信息素蒸发系数 G 20…

嵌入式学习笔记——STM32硬件基础知识

STM32开发硬件知识前言STM32最小系统电源电路晶振电路复位电路BOOT选择电路调试接口电路其他电路本文重点本文参考博客链接前言 上一篇中我们重点是讲了一下怎么搭建开发环境以及怎么下载烧录的过程&#xff0c;这都是解决的电脑端的开发环境问题&#xff0c;还没有到实际的开…

【C++初阶】list的使用

大家好我是沐曦希&#x1f495; 文章目录一、前言二、构造三、迭代器四、增删查改1.头插头删2.尾插尾删3.查找和插入4.删除五、其他成员函数1.排序和去重2.splice和remove3.resize一、前言 list本质是带头双向循环链表&#xff0c;本文只对list的一些常用接口进行说明&#xf…

用逻辑回归制作评分卡

目录 一.评分卡 二.导库&#xff0c;获取数据 三.探索数据与数据预处理 1.去除重复值 2.填补缺失值 3.描述性统计处理异常值 4.为什么不统一量纲&#xff0c;也不标准化数据分布 5.样本不均衡问题 6.分训练集和测试集 三.分箱 1.分多少个箱子才合适 2.分箱要达成什么…

真香,Grafana开源Loki日志系统取代ELK?

一、Loki是什么&#xff1f; Loki是由Grafana Labs开源的一个水平可扩展、高可用性&#xff0c;多租户的日志聚合系统的日志聚合系统。它的设计初衷是为了解决在大规模分布式系统中&#xff0c;处理海量日志的问题。Loki采用了分布式的架构&#xff0c;并且与Prometheus、Graf…

51单片机入门————数码管显示

我们在马路上看到的红绿灯&#xff0c;就是由数码管来实现的&#xff0c;就是其中可能加入了一些延时和转换数码管是通过控制138译码器与74HC245来控制数码管的亮灭与数字的显示电路原理图我们先讨论一个数码管数码管有共阳极和共阴极&#xff0c;我们现在使用的STC89C52是共阴…

Linux用户空间与内核空间通信(Netlink通信机制)

一&#xff0c;什么是Netlink通信机制 Netlink是linux提供的用于内核和用户态进程之间的通信方式。但是注意虽然Netlink主要用于用户空间和内核空间的通信&#xff0c;但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式&#xff0c;一般不用Netlink。除非需要…