【学习记录】AVL树及相关链表,线程池实现

本来打算使用avl树套链表的结构,来避免优先级相等的情况,但是最后发现当绝大多数优先级都相等,avl树还是不可避免的退化成单链表,而需求中也确实是绝大多数都是优先级相等。

所以评估之后觉得avl树带来的提升远不及其提升的复杂度,所以放弃该方案,改为链表实现,现将此前实验的代码整理如下,

AVL树部分应该没有问题。重要步骤做了注释

.c文件如下

c 复制代码
//
// Created by Administrator on 2025/2/10.
//
#ifdef __cplusplus
extern "C" {
#endif
#include "threadpool.h"
#include <malloc.h>
#include <pthread.h>
#include "string.h"
///---------------------------链表操作----------------

/**
 * @brief 比较两个节点的数据
 * @param 数据1
 * @param 数据2
 * @return 0-相等 -1-不相等
 * */
int compare_node(Task_t target1,Task_t target2){
    return (target1.func == target2.func)&&(strncmp(target1.task_name,target2.task_name,strlen(target2.task_name))==0)&&(target1.priority == target2.priority);
}

//在尾巴插入一个节点
int list_insert_r(AVLData * list_head,AVLData new_node){
    if (list_head == NULL) return 0;
//    if (new_node == NULL) return 0; //新建数据节点必须在之前分配好内存
    AVLData * newnode = (AVLData *)malloc(sizeof(AVLData));
    if(newnode == NULL){
        return -1; //内存开辟失败
    }
    (*newnode)=new_node;
    AVLData * p= list_head;
    //设置新节点数据
    newnode->next = NULL;
    newnode->key=newnode->task.priority;
    while (p->next){//第一个节点不存数据
        p=p->next;
    }
    p->next = newnode;
    return 0;
}
/**
 * @brief 删除节点,对比任务名,任务优先级和任务函数指针,全部一样删除
 * @param list_head 链表头
 * @param del_node 要删除的节点
 * @return 0-删除成功 -1-删除失败
 * */
int list_node_del(AVLData * list_head,Task_t del_node){
    AVLData * p = list_head;
    while (p->next){//
        if(compare_node(p->next->task,del_node)==0){ //如果相等
            break;
        }
        p = p->next;
    }
    if(p->next == NULL )
        return -1; //未找到
    AVLData * q = p->next;
    p->next = p->next->next;
    free(q);
    return 0;
}
/**
 * @brief 遍历节点
 * @param list_head 链表首元结点
 * */
int list_traverse(AVLData * list_head){
    AVLData * p = list_head;
    p=p->next;
    while (p){
        printf("节点数据\n");
        p=p->next;
    }
    return 0;
}




///---------------------------AVL树----------------
// 获取节点高度
int get_avltree_height(AVLNode *node) {
    if (node == NULL) return 0;
    return node->height;
}

// 新建节点
AVLNode* avltree_newNode(AVLData data) {
    AVLNode* node = (AVLNode*) malloc(sizeof(AVLNode));
    if(node == NULL){
        _exit(-1);//申请内存失败
    }
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    node->height = 1; // 新节点初始高度设为1
    return node;
}

// 右旋
AVLNode *rightRotate(AVLNode *y) {
    AVLNode *x = y->left;
    AVLNode *T2 = x->right;

    x->right = y; //自身插入原来自己左孩子的右节点 完成右旋
    y->left = T2; //冲突的右孩变左孩

    y->height = 1 + (get_avltree_height(y->left) > get_avltree_height(y->right) ? get_avltree_height(y->left) : get_avltree_height(y->right));
    x->height = 1 + (get_avltree_height(x->left) > get_avltree_height(x->right) ? get_avltree_height(x->left) : get_avltree_height(x->right));

    return x;
}

// 左旋
AVLNode *leftRotate(AVLNode *x) {
    AVLNode *y = x->right;
    AVLNode *T2 = y->left;

    y->left = x; //原来节点变成其右孩子的左孩子 完成左旋
    x->right = T2; //冲突左孩变右孩

    //重新计算高度 左右孩子中最高的+自身
    x->height = 1 + (get_avltree_height(x->left) > get_avltree_height(x->right) ? get_avltree_height(x->left) : get_avltree_height(x->right));
    y->height = 1 + (get_avltree_height(y->left) > get_avltree_height(y->right) ? get_avltree_height(y->left) : get_avltree_height(y->right));

    return y;
}

// 获取平衡因子
int getBalanceFactor(AVLNode *N) {
    if (N == NULL) return 0;
    return get_avltree_height(N->left) - get_avltree_height(N->right);
}

// 插入节点
AVLNode* avltree_insert(AVLNode* node, AVLData data) {
    if (node == NULL)
        return avltree_newNode(data);

    if (data.key < node->data.key) //小的靠左
        node->left  = avltree_insert(node->left, data);
    else if (data.key > node->data.key)
        node->right = avltree_insert(node->right, data);
    else{//相同节点这个需要在进行处理,考虑在该节点处增加链表存储相同优先级的
        list_insert_r(&node->data,data); //在当前节点的数据链表后插入
        return node;
    }


    node->height = 1 + (get_avltree_height(node->left) > get_avltree_height(node->right) ? get_avltree_height(node->left) : get_avltree_height(node->right));

    int balance = getBalanceFactor(node);

    if (balance > 1 && data.key < node->left->data.key) // LL型 右旋
        return rightRotate(node);
    if (balance < -1 && data.key > node->right->data.key) // RR型 左旋
        return leftRotate(node);
    if (balance > 1 && data.key > node->left->data.key) { //LR型 左旋左孩子 然后右旋
        node->left =  leftRotate(node->left);
        return rightRotate(node);
    }
    if (balance < -1 && data.key < node->right->data.key) { //RL型 右旋右孩子 然后左旋
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }

    return node;
}

// 查找最小值节点
AVLNode * minValueNode(AVLNode* node) {
    AVLNode* current = node;
    while (current->left != NULL)
        current = current->left;
    return current;
}

// 删除节点
AVLNode* avltree_deleteNode(AVLNode* root, AVLData data) {
    if (root == NULL)
        return root;

    if ( data.key < root->data.key )
        root->left = avltree_deleteNode(root->left, data);
    else if( data.key > root->data.key )
        root->right = avltree_deleteNode(root->right, data);
    else { //等于的情况
        if((root->left == NULL) || (root->right == NULL)) { //如果是叶子节点
            AVLNode *temp = root->left ? root->left : root->right;

            if (temp == NULL) { //没有子树
                temp = root;
                root = NULL; //如果是叶子节点 直接删除 这一步在返回时会赋值给上一层的 root->left 或者  root->right
            } else //有一个子树
                *root = *temp; // 单边为空 复制非空子项的内容 然后将节点删除
            free(temp);
        } else { //两边都不为空 两个子树
            AVLNode* temp = minValueNode(root->right);//找到后驱节点 右边最接近删除节点的值
            root->data = temp->data;  //只替换值 保留左右子树和高度信息

            root->right = avltree_deleteNode(root->right, temp->data); //将后驱节点删除,此时后驱节点必然是只有一个子树或者没有子树,坍缩为之前两种情况
        }
    }

    if (root == NULL)
        return root;

    root->height = 1 + (get_avltree_height(root->left) > get_avltree_height(root->right) ? get_avltree_height(root->left) : get_avltree_height(root->right));

    int balance = getBalanceFactor(root);

    if (balance > 1 && getBalanceFactor(root->left) >= 0) //LL
        return rightRotate(root);

    if (balance > 1 && getBalanceFactor(root->left) < 0) { //LR
        root->left = leftRotate(root->left);
        return rightRotate(root);
    }

    if (balance < -1 && getBalanceFactor(root->right) <= 0) //RR
        return leftRotate(root);

    if (balance < -1 && getBalanceFactor(root->right) > 0) {//RL
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }

    return root;
}

// 中序遍历打印
void inorderTraversal(AVLNode *root) {
    if(root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->data.key);
        inorderTraversal(root->right);
    }
}

/// ------------------------------线程池操作------------------------------------








void* thread_worker(void *arg) {
    Thread_pool_t *pool = (Thread_pool_t*)arg;
    while (1) {
        pthread_mutex_lock(&pool->lock);

//        // 调整队列中的任务优先级
//        adjust_priority(pool->task_queue, pool->queue_start, pool->queue_end, pool->queue_size);
//
//        while (pool->queue_count == 0 && !pool->shutdown) {
//            pthread_cond_wait(&pool->cond, &pool->lock);
//        }
//        if (pool->shutdown) {
//            pthread_mutex_unlock(&pool->lock);
//            pthread_exit(NULL);
//        }
//
//        task_t *task = pool->task_queue[pool->queue_start];
//        if (task->exec_count > 0 && difftime(time(NULL), task->last_exec_time) >= task->interval) {
//            pool->queue_start = (pool->queue_start + 1) % pool->queue_size;
//            pool->queue_count--;
//
//            task->func(task->arg); // 执行任务
//            task->last_exec_time = time(NULL);
//            if (--task->exec_count > 0) {
//                insert_task_by_priority(pool->task_queue, task, &pool->queue_start, &pool->queue_end, &pool->queue_count, pool->queue_size);
//            } else {
//                free(task);
//            }
//        } else {
//            pthread_mutex_unlock(&pool->lock);
//            continue;
//        }
        pthread_mutex_unlock(&pool->lock);
    }
    return NULL;
}




Thread_pool_t* thread_pool_init(int num_workers, int queue_size) {
    Thread_pool_t *pool = (Thread_pool_t *)malloc(sizeof(Thread_pool_t));
    if (pool == NULL) return NULL;

    pool->num_workers = num_workers;
    pool->queue_size = queue_size;
    pool->workers = (pthread_t *)malloc(num_workers * sizeof(pthread_t));
    pool->task_queue = (Task_t**)malloc(queue_size * sizeof(Task_t*));
    pool->queue_start = 0;
    pool->queue_end = 0;
    pool->queue_count = 0;
    pool->shutdown = 0;

    pthread_mutex_init(&pool->lock, NULL);
    pthread_cond_init(&pool->cond, NULL);

    for (int i = 0; i < num_workers; ++i) {
        if (pthread_create(&pool->workers[i], NULL, thread_worker, pool) != 0) {
            fprintf(stderr, "线程创建失败\n");
            _exit(-1);
        }
    }

    return pool;
}

void insert_task_by_priority(Task_t **queue, Task_t *task, int *queue_start, int *queue_end, int *queue_count, int queue_size) {
    int pos = *queue_end;
    while (pos != *queue_start) {
        int prev_pos = (pos - 1 + queue_size) % queue_size;
        if (queue[prev_pos]->priority <= task->priority) break;
        queue[pos] = queue[prev_pos];
        pos = prev_pos;
    }
    queue[pos] = task;
    *queue_end = (*queue_end + 1) % queue_size;
    (*queue_count)++;
}


/**
 * @param pool 线程池
 * @param func 任务
 * @param arg 任务参数
 * @param priority 任务优先级
 * @param exec_count 任务循环次数
 * @param interval 任务执行间隔时间
 * */
int thread_pool_submit(Thread_pool_t *pool, task_func func, void *arg, int priority, int exec_count, int interval) {
    if (pool->queue_count == pool->queue_size) return -1;


    Task_t *task = (Task_t *)malloc(sizeof(Task_t));
    task->func = func;
    task->arg = arg;
    task->priority = priority;
    task->exec_count = exec_count;
    task->last_exec_time = time(NULL) - interval - 1; // 确保首次可以被执行
    task->interval = interval;

    pthread_mutex_lock(&pool->lock);
    insert_task_by_priority(pool->task_queue, task, &pool->queue_start, &pool->queue_end, &pool->queue_count, pool->queue_size);
    pthread_cond_signal(&pool->cond);
    pthread_mutex_unlock(&pool->lock);

    return 0;
}




#ifdef __cplusplus
}
#endif

.h文件如下

c 复制代码
//
// Created by Administrator on 2025/2/10.
//
#ifndef DEVP_THREADPOOL_H
#define DEVP_THREADPOOL_H

#ifdef __cplusplus
extern "C" {
#endif
#include <time.h>
#include <pthread.h>
#include <unistd.h>
typedef void (*task_func)(void*);
typedef struct {
    task_func func;             // 任务函数
    char task_name[128];        // 任务名称
    void* arg;                  // 任务参数
    int priority;               // 任务优先级
    int exec_count;             // 执行次数
    long int last_exec_time;    // 上次执行时间
    long int interval;          // 执行间隔时间(ms)
}Task_t;

// 线程池结构体
typedef struct {
    int num_workers;            //工作线程数
    pthread_t *workers;
    Task_t **task_queue;
    int queue_size;             //最大任务数
    int queue_start;
    int queue_end;
    int queue_count;
    pthread_mutex_t lock;
    pthread_cond_t cond;
    int shutdown;                   //线程退出
}Thread_pool_t;


///------------------------------------AVL树相关------------------------------------------

typedef struct avldata{
    Task_t task; //保留一个首元结点不放数据
    struct avldata *next ; //这里做链表来存储 相同优先级的任务
    int key; //这里是key作为AVL树来排序的依据,默认和task内部的优先级相同,当然也可以绑定其它的数值
}AVLData;


// 定义AVL树节点
typedef struct AVLNode {
    AVLData data;
    struct AVLNode *left;
    struct AVLNode *right; //作为树时使用
//    struct AVLNode *next;  //作为链表时使用
    int height;
}AVLNode;




#ifdef __cplusplus
}
#endif


#endif //DEVP_THREADPOOL_H
相关推荐
song_ly00118 分钟前
深入理解软件测试覆盖率:从概念到实践
笔记·学习·测试
DIY机器人工房43 分钟前
[6-2] 定时器定时中断&定时器外部时钟 江协科技学习笔记(41个知识点)
笔记·stm32·单片机·学习·江协科技
IT专业服务商1 小时前
联想 SR550 服务器,配置 RAID 5教程!
运维·服务器·windows·microsoft·硬件架构
海尔辛1 小时前
学习黑客5 分钟小白弄懂Windows Desktop GUI
windows·学习
gushansanren1 小时前
基于WSL用MSVC编译ffmpeg7.1
windows·ffmpeg
伐尘3 小时前
【Qt】编译 Qt 5.15.x For Windows 基础教程 Visual Studio 2019 MSVC142 x64
windows·qt·visual studio
专注代码七年3 小时前
在Windows 境下,将Redis和Nginx注册为服务。
windows·redis·nginx
烟雨迷3 小时前
Linux环境基础开发工具的使用(yum、vim、gcc、g++、gdb、make/Makefile)
linux·服务器·学习·编辑器·vim
@十八子德月生3 小时前
8天Python从入门到精通【itheima】-1~5
大数据·开发语言·python·学习
Clockwiseee5 小时前
文件上传总结
运维·服务器·学习·文件上传