C-线程池

news/2024/7/27 11:21:23/文章来源:https://blog.csdn.net/qq_34486832/article/details/136722715

1、介绍

一个线程池由三部分组成:
        (1)管理者线程,用于实时判断线程池中的任务个数、线程个数;并根据两者之间的变化来创建或销毁线程,与任务队列达到平衡。对应于示例中的thread_manage()函数。
        (2)工作线程,线程池中线程,个数不定,在没有任务时处于等待状态,可以循环的执行任务。对应于示例中的thread_work()函数。
        (3)任务队列,用于存放没有处理的任务,链表、数组等结构存储。

2、示例

代码参考:

        手写线程池 - C语言版 | 爱编程的大丙

        C语言实现简单的线程池项目(附完整工程文件)_线程池项目文档-CSDN博客

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>typedef struct TaskiLists
{void (*function)(void* arg);void* arg;
}TaskLists;struct ThreadPool
{// 任务队列TaskLists* task_list;// 任务队列的容量int task_list_cap;// 当前任务队列中任务的数量int task_list_size;// 任务队列队头数据int task_list_front;// 任务队列队尾数据int task_list_rear;// 线程池中线程队列pthread_t* threads_id;// 线程池中线程的最大数量int threads_max;// 线程池中线程的最小数量int threads_min;// 工作的线程个数int threads_busy_num;// 存活的线程个数int threads_live_num;// 要销毁的线程个数int threads_exit_num;// 管理者线程pthread_t thread_manage;// 锁  锁住整个线程池pthread_mutex_t lock_pool;// 锁  锁住threads_busy_num变量pthread_mutex_t lock_threads_busy_num;// 条件变量  task_list是不是达到最大容量pthread_cond_t task_list_full;// 条件变量  task_list是不是为空pthread_cond_t task_list_empty;// 是否销毁线程,销毁=1;不销毁=0int shut_down;
};typedef struct ThreadPool ThreadPool;//############################################################################################################
//############################################################################################################// 给线程池添加任务
void thread_pool_add(ThreadPool* pool, void(*func)(void*), void* arg)
{pthread_mutex_lock(&(pool->lock_pool));// 如果任务列表已满,添加进程阻塞while (pool->task_list_size == pool->task_list_cap && pool->shut_down == 0){pthread_cond_wait(&(pool->task_list_full), &(pool->lock_pool));}// 如果线程池要关闭了,直接返回if (pool->shut_down == 1){pthread_mutex_unlock(&(pool->lock_pool));return;}// 添加任务pool->task_list[pool->task_list_rear].function = func;pool->task_list[pool->task_list_rear].arg = arg;pool->task_list_size += 1;pool->task_list_rear = (pool->task_list_rear + 1) % pool->task_list_cap;printf("--------- add %d %ld\n", pool->task_list_size, pthread_self());// 通过条件变量通知任务开始处理pthread_cond_signal(&(pool->task_list_empty));pthread_mutex_unlock(&(pool->lock_pool));return;
}// 销毁一个线程
void thread_exit(ThreadPool* pool)
{pthread_t tid = pthread_self();for (int i = 0; i < pool->threads_max; i++){if (pool->threads_id[i] == tid){pool->threads_id[i] = 0;printf("threadExit() called, %ld exiting...\n", tid);break;}}pthread_exit(NULL);
}void thread_work(void* arg)
{ThreadPool* pool = (ThreadPool*)arg;// 工作线程要一直在执行,时时执行while (1){sleep(1.3);pthread_mutex_lock(&(pool->lock_pool));// 如果任务列表为空,添加进程阻塞while (pool->task_list_size == 0 && pool->shut_down == 0){pthread_cond_wait(&(pool->task_list_empty), &(pool->lock_pool));if (pool->threads_exit_num > 0){pool->threads_exit_num--;if (pool->threads_live_num > pool->threads_min){pool->threads_live_num--;pthread_mutex_unlock(&(pool->lock_pool));// 销毁该线程thread_exit(pool);}}}// 如果线程池要关闭了,直接返回if (pool->shut_down == 1){pthread_mutex_unlock(&(pool->lock_pool));thread_exit(pool);}// 取任务参数TaskLists tmp;tmp.function = pool->task_list[pool->task_list_front].function;tmp.arg = pool->task_list[pool->task_list_front].arg;pool->task_list_size--;pool->task_list_front = (pool->task_list_front + 1) % pool->task_list_cap;  // 向后偏移// 条件变量,通知pthread_cond_signal(&pool->task_list_full);pthread_mutex_unlock(&(pool->lock_pool));// 处理任务printf("thread %ld start working...\n", pthread_self());pthread_mutex_lock(&(pool->lock_threads_busy_num));pool->threads_busy_num += 1;pthread_mutex_unlock(&(pool->lock_threads_busy_num));tmp.function(tmp.arg);free(tmp.arg);tmp.arg = NULL;printf("thread %ld end working...\n", pthread_self());pthread_mutex_lock(&(pool->lock_threads_busy_num));pool->threads_busy_num--;pthread_mutex_unlock(&(pool->lock_threads_busy_num));}return;
}// 管理者线程  管理代码处理
void thread_manage(void* arg)
{ThreadPool* pool = (ThreadPool*)arg;while (pool->shut_down == 0){printf("===========================\n");// 每3s检测一次pool的状态sleep(3);// 取出线程池中任务的数量和当前线程的数量pthread_mutex_lock(&(pool->lock_pool));int task_list_size = pool->task_list_size;int threads_live_num = pool->threads_live_num;pthread_mutex_unlock(&pool->lock_pool);// 取出工作的线程的数量pthread_mutex_lock(&pool->lock_threads_busy_num);int threads_busy_num = pool->threads_busy_num;pthread_mutex_unlock(&pool->lock_threads_busy_num);// 添加线程// 任务的个数 > 存活的线程个数 && 存活的线程数 < 最大线程数if (task_list_size > threads_live_num && threads_live_num < pool->threads_max){pthread_mutex_lock(&(pool->lock_pool));int cnt = 0;for (int i = 0; i < pool->threads_max && cnt < task_list_size && pool->threads_live_num < pool->threads_max; i++){if (pool->threads_id[i] == 0){pthread_create(&(pool->threads_id[i]), NULL, thread_work, pool);cnt += 1;pool->threads_live_num += 1;}}pthread_mutex_unlock(&pool->lock_pool);}// 销毁线程// 忙的线程*2 < 存活的线程数 && 存活的线程 > 最小线程数if (threads_busy_num * 2 < threads_live_num && threads_live_num > pool->threads_min){pthread_mutex_lock(&(pool->lock_pool));pool->threads_exit_num = threads_busy_num > pool->threads_min ? threads_busy_num : pool->threads_min;pthread_mutex_unlock(&(pool->lock_pool));// 让工作的线程自杀for (int i = 0; i < pool->threads_exit_num; i++){pthread_cond_signal(&(pool->task_list_empty));}}}return;
}// 创建线程池
ThreadPool* thread_pool_create(int max, int min, int task_list_cap)
{// 申请线程池结构体内容存放的地址ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));if (pool == NULL){printf("the pool malloc failed...\n");return NULL;}// 申请线程数组pool->threads_id = (pthread_t*)malloc(sizeof(pthread_t) * max);if (pool->threads_id == NULL) {printf("malloc threadIDs fail...\n");return NULL;}memset(pool->threads_id, 0, sizeof(pthread_t) * max);pool->threads_max = max;pool->threads_min = min;pool->threads_busy_num = 0;pool->threads_live_num = min;   // 线程池中最少有min线程在启动,但是有可能不再工作pool->threads_exit_num = 0;     // 需要销毁的线程个数;任务少的时候,大多数线程空闲时,需要销毁// 创建线程for (int i = 0; i < min; i++){pthread_create(&(pool->threads_id[i]), NULL, thread_work, pool);}// 管理者线程pool->thread_manage  = (pthread_t*)malloc(sizeof(pthread_t));if (pool->thread_manage == NULL) {printf("malloc manage thread fail...\n");return NULL;}pthread_create(&(pool->thread_manage), NULL, thread_work, pool);// 任务队列初始化pool->task_list = (TaskLists*)malloc(sizeof(TaskLists) * task_list_cap);if (pool->task_list == NULL){printf("the task list init failed...\n");return NULL;}pool->task_list_cap = task_list_cap;pool->task_list_front = 0;pool->task_list_rear = 0;// 初始化锁和条件变量if (pthread_mutex_init(&(pool->lock_pool), NULL) != 0 || pthread_mutex_init(&(pool->lock_threads_busy_num), NULL) != 0 ||pthread_cond_init(&(pool->task_list_full), NULL) != 0 || pthread_cond_init(&(pool->task_list_empty), NULL) != 0){printf("mutex or condition init fail...\n");return;}pool->shut_down = 0;printf("----------------------- init success.\n");return pool;
}// 销毁线程池
void thread_pool_destory(ThreadPool* pool)
{if (pool == NULL){return;}// 关闭线程池pool->shut_down = 1;// 阻塞回收管理者线程pthread_join(&(pool->thread_manage), NULL);// 唤醒阻塞的消费者线程for (int i = 0; i < pool->threads_live_num; i++){pthread_cond_signal(&(pool->task_list_empty));}// 释放内存,申请的时候是一次申请出来的(一个数组),释放的时候也一样if (pool->threads_id != NULL){free(pool->threads_id);}// 释放内存,申请的时候是一次申请出来的,释放的时候也一样if (pool->task_list != NULL){free(pool->task_list);}pthread_mutex_lock(&(pool->lock_pool));               /*先锁住再销毁*/pthread_mutex_destroy(&(pool->lock_pool));pthread_mutex_lock(&(pool->lock_threads_busy_num));pthread_mutex_destroy(&(pool->lock_threads_busy_num));pthread_cond_destroy(&(pool->task_list_full));pthread_cond_destroy(&(pool->task_list_empty));// 释放内存free(pool);return;
}// 实际的处理函数
void taskFunc(void* arg)
{int num = *(int*)arg;printf("thread %ld is working, number = %d\n", pthread_self(), num);
}int main()
{ThreadPool* pool = thread_pool_create(10, 3, 100);for (int i = 0; i < 50; i++){int* num = (int*)malloc(sizeof(int));*num = i + 100;thread_pool_add(pool, taskFunc, num);sleep(2);}sleep(30);thread_pool_destory(pool);return 0;
}

结果:

----------------------- init success.
--------- add 1 140196491261696
--------- add 2 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 100
thread 140196491253504 start working...
thread 140196491253504 is working, number = 101
thread 140196491253504 end working...
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 102
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 103
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 104
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 105
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 106
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 107
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 108
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 109
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 110
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 111
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 112
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 113
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 114
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 115
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 116
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 117
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 118
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 119
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 120
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 121
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 122
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 123
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 124
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 125
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 126
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 127
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 128
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 129
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 130
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 131
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 132
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 133
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 134
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 135
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 136
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 137
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 138
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 139
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 140
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 141
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 142
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 143
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 144
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 145
thread 140196491253504 end working...
--------- add 1 140196491261696
thread 140196466075392 start working...
thread 140196466075392 is working, number = 146
thread 140196466075392 end working...
--------- add 1 140196491261696
thread 140196474468096 start working...
thread 140196474468096 is working, number = 147
thread 140196474468096 end working...
--------- add 1 140196491261696
thread 140196482860800 start working...
thread 140196482860800 is working, number = 148
thread 140196482860800 end working...
--------- add 1 140196491261696
thread 140196491253504 start working...
thread 140196491253504 is working, number = 149
thread 140196491253504 end working...
threadExit() called, 140196474468096 exiting...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1007567.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信号与系统学习笔记——信号的分类

目录 一、确定与随机 二、连续与离散 三、周期与非周期 判断是否为周期函数 离散信号的周期 结论 四、能量与功率 定义 结论 五、因果与反因果 六、阶跃函数 定义 性质 七、冲激函数 定义 重要关系 作用 一、确定与随机 确定信号&#xff1a;可以确定时间函数…

阿里云免费证书改为3个月,应对方法很简单

情商高点的说法是 Google 积极推进90天免费证书&#xff0c;各服务商积极响应。 情商低点的话&#xff0c;就是钱的问题。 现在基本各大服务商都在2024年停止签发1年期的免费SSL证书产品&#xff0c;有效期都缩短至3个月。 目前腾讯云倒还是一年期。 如果是一年期的话&#x…

冒泡排序,详详解解

目录 基本概念&#xff1a; 上图&#xff1a; 核心思路&#xff1a; 基本步骤&#xff1a; 关键&#xff1a; 代码核心&#xff1a; 补充&#xff1a; 代码&#xff08;规范&#xff09; &#xff1a; 代码&#xff08;优化&#xff09;&#xff1a; 今天我们不刷力扣了&…

CSDN 编辑器设置图片缩放和居中

CSDN 编辑器设置图片缩放和居中 文章目录 CSDN 编辑器设置图片缩放和居中对齐方式比例缩放 对齐方式 Markdown 编辑器插入图片的代码格式为 ![图片描述](图片路径)CSDN 的 Markdown 编辑器中插入图片&#xff0c;默认都是左对齐&#xff0c;需要设置居中对齐的话&#xff0c;…

ChatGPT-Next-Web SSRF漏洞+XSS漏洞复现(CVE-2023-49785)

0x01 产品简介 ChatGPT-Next-Web 是一种基于 OpenAI 的 GPT-3.5 、GPT-4.0语言模型的产品。它是设计用于 Web 环境中的聊天机器人,旨在为用户提供自然语言交互和智能对话的能力。 0x02 漏洞概述 2024年3月,互联网上披露CVE-2023-49785 ChatGPT-Next-Web SSRF/XSS 漏洞,未经…

CompletableFuture原理与实践-外卖商家端API的异步化

背景 随着订单量的持续上升&#xff0c;美团外卖各系统服务面临的压力也越来越大。作为外卖链路的核心环节&#xff0c;商家端提供了商家接单、配送等一系列核心功能&#xff0c;业务对系统吞吐量的要求也越来越高。而商家端API服务是流量入口&#xff0c;所有商家端流量都会由…

IDEA如何删除git最新一次远程提交

IDEA如何删除git最新一次远程提交 选择应用 -> Git -> Show History 选择最新提交上一次提交 -> Reset Current Branch to Here… Reset 提示框选择 Hard push到远程分支 -> 选择Force Push 结果验证 &#xff08;最新分支已被删除&#xff09;

Docker-基本命令

目录 一、Docker与虚拟机技术 二、Docker功能 三、安装 安装&#xff1a; 1、环境准备&#xff1a; 2、安装docker 3、配置阿里云镜像加速 镜像加速源 4、Docker是怎么工作的 5、Docker为什么比虚拟机快 四、docker命令 1、镜像命令 Docker官方镜像库&#xff1a…

小程序学习3 goods-card

pages/home/home home.wxml <goods-listwr-class"goods-list-container"goodsList"{{goodsList}}"bind:click"goodListClickHandle"bind:addcart"goodListAddCartHandle"/> <goods-list>是一个自定义组件&#xff0c;它具…

什么是制作视频内容?如何搞好视频内容制作?

写在前面 视频内容已成为希望吸引数字观众的企业、品牌和创作者的必备资产。事实上&#xff0c;根据NogenTech的一份报告&#xff0c;在2023年&#xff0c;91%的营销部门使用了这种动态内容。 视频内容创作和优化性能的技巧和窍门的增加绝非巧合。TikTok以及Instagram Reels和…

BMJ杂志方法学推荐:断点回归方法

直播课程 郑老师本周六&#xff1a;真实世界临床研究直播课&#xff08;点击了解详情&#xff09; 2024年2月27日&#xff0c;顶级医学期刊BMJ发表了一篇有关断点回归设计研究的指南&#xff0c;文中所介绍的断点回归既具有类似随机对照组的优势&#xff0c;又能依托于观察性研…

软考--软件设计师(磁盘管理的例题)

流水线的理论公式&#xff1a; 单缓冲区&#xff1a;同一时间内只能允许一个进程进行写入读出&#xff0c;所以每个盘块经过缓冲区的时间是&#xff08;155微秒&#xff09;&#xff0c;之后再用1微秒的时间进行处理。在处理的同时&#xff0c;下一个盘块写入缓冲区&#xff0c…

增删卜易——八宫六十四卦

之前看倪海厦的《天纪》笔记里面提到了六十四卦世应,觉得不知道这个世应是啥意思。很长时间就没看了,偶然间看到了张文江教授写的一本书《潘雨廷先生谈话录》提到了《卜筮正宗》,“卜筮最后的判断是非理性转义,其他一切都只是形式”,“明人的著作,从京氏易出,如今天几日…

Kubernetes Prometheus 系列|Prometheus介绍和使用|Prometheus+Grafana集成

目录 第1章Prometheus 入门1.1 Prometheus 的特点1.1.1 易于管理1.1.2 监控服务的内部运行状态1.1.3 强大的数据模型1.1.4 强大的查询语言 PromQL1.1.5 高效1.1.6 可扩展1.1.7 易于集成1.1.8 可视化1.1.9 开放性 1.2 Prometheus 的架构1.2.1 Prometheus 生态圈组件1.2.2 架构理…

【C++ 】stack 和 queue

1. 标准库中的stack stack 的介绍&#xff1a; 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行 元素的插入与提取操作 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其…

PyQt4应用程序的PDF查看器

最近因为项目需要创建一个基于PyQt4的PDF查看器应用程序&#xff0c;正常来说&#xff0c;我们可以使用PyQt4的QtWebKit模块来显示PDF文件。那么具体怎么实现呢 &#xff1f;以下就是我写的一个简单的示例代码&#xff0c;演示如何创建一个PyQt4应用程序的PDF查看器&#xff1a…

如何在CentOS7搭建DashDot服务器仪表盘并实现远程监控

文章目录 1. 本地环境检查1.1 安装docker1.2 下载Dashdot镜像 2. 部署DashDot应用3. 本地访问DashDot服务4. 安装cpolar内网穿透5. 固定DashDot公网地址 本篇文章我们将使用Docker在本地部署DashDot服务器仪表盘&#xff0c;并且结合cpolar内网穿透工具可以实现公网实时监测服务…

解决iview表格固定列横向滚动条无法拖动问题

问题描述&#xff1a; iview的table添加固定列以后&#xff0c;滚动条在固定列下面无法拖动&#xff0c;只能在滚动区域有所反应 解决办法 【写入main.js引入的全局文件时不需要::v-deep; 写入单个文件需要加::v-deep】 方法一&#xff1a;【带合计行也适用】 //解决iview表…

java数据结构与算法刷题-----LeetCode47. 全排列 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 暴力回溯2. 分区法回溯 此题为46题的衍生题&#xff0c;在46题…

力扣热题100_矩阵_48_旋转图像

文章目录 题目链接解题思路解题代码 题目链接 48.旋转图像 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1…