C语言 | Leetcode C语言题解之第432题全O(1)的数据结构

news2024/11/15 4:57:52

题目:

题解:

//哈希+队列
//哈希检查是否存在
//双编标维护次数顺序
#define MAXSIZE 769/* 选取一个质数即可 */
typedef struct hashNode
{
    char* string;     //字符串
    int                       count;       //次数
    struct doubleListNode* dList;
    struct hashNode* next;      //保存链表表头
} hashMapList;

typedef struct
{
    hashMapList* hashHead[MAXSIZE];//定义哈希数组的大小
} MyHashMap;

typedef struct doubleListNode
{
    hashMapList* pHashMap;
    struct doubleListNode* prev;  //前一个指针域
    struct doubleListNode* next;  //下一个指针域
}doubleList;

typedef struct
{
    doubleList* front;       //头部指针
    doubleList* rear;        //尾部指针
    int count;
} MyQueueList;

typedef struct
{
    MyQueueList* doublelist;
    MyHashMap* hashmap;
} AllOne;


AllOne* allOneCreate()
{
    AllOne* newAllone = (AllOne*)malloc(sizeof(AllOne));
    MyHashMap* newHash = (MyHashMap*)malloc(sizeof(MyHashMap));
    MyQueueList* newList = (MyQueueList*)malloc(sizeof(MyQueueList));
    //哈希初始化
    for (int i = 0; i < MAXSIZE; i++)
    {
        newHash->hashHead[i] = NULL;
    }
    //队列初始化
    newList->front = NULL;
    newList->rear = NULL;
    newAllone->hashmap = newHash;
    newAllone->doublelist = newList;
    newAllone->doublelist->count = 0;
    return newAllone;
}

//哈希代码
hashMapList* isInHash(hashMapList* list, char* stringKey)
{
    hashMapList* nodeIt = list;
    //通过链表下遍历
    while (nodeIt != NULL)
    {
        if (strcmp(stringKey, nodeIt->string) == 0)
        {
            return nodeIt;
        }
        nodeIt = nodeIt->next;
    }
    return NULL;
}


hashMapList* myHashMapPut(MyHashMap* obj, char* stringKey, int count)
{
    hashMapList* newNode = (hashMapList*)malloc(sizeof(hashMapList));
    newNode->string = stringKey;
    newNode->next = NULL;
    newNode->count = count;
    if (obj->hashHead[stringKey[0] % MAXSIZE] != NULL)
    {
        //当前头链表不为空,则需要将后续的链表接上
        //需要主要这里表头也代表一个数据的值
        newNode->next = obj->hashHead[stringKey[0] % MAXSIZE];
    }
    //修改头链表
    obj->hashHead[stringKey[0] % MAXSIZE] = newNode;
    return newNode;
}

hashMapList* myHashMapGet(MyHashMap* obj, char* stringKey)
{
    hashMapList* hashMapIt = isInHash(obj->hashHead[stringKey[0] % MAXSIZE], stringKey);
    if (hashMapIt != NULL)
    {
        return hashMapIt;
    }
    return NULL;
}

void myHashMapRemove(MyHashMap* obj, char* key)
{
    hashMapList* nodePre = NULL;
    hashMapList* nodeIt = obj->hashHead[key[0] % MAXSIZE];


    //通过链表下遍历
    while (nodeIt != NULL)
    {
        if (strcmp(key, nodeIt->string) == 0)
        {
            break;
        }
        nodePre = nodeIt;
        nodeIt = nodeIt->next;
    }

    //找到了
    if (nodePre == NULL)
    {
        //等于表头
        obj->hashHead[key[0] % MAXSIZE] = nodeIt->next;
    }
    else
    {
        nodePre->next = nodeIt->next;
    }
    free(nodeIt);
}


void myHashMapFree(MyHashMap* obj)
{
    int i;
    hashMapList* freeIt;
    hashMapList* curIt;
    for (i = 0; i < MAXSIZE; i++)
    {
        if (obj->hashHead[i] != NULL)
        {
            freeIt = NULL;
            curIt = obj->hashHead[i];

            while (curIt != NULL)
            {
                freeIt = curIt;
                curIt = curIt->next;
                free(freeIt);
            }
            obj->hashHead[i] = NULL;
        }
    }
    free(obj);
}


//双链表代码
void myLinkedListFree(MyQueueList* obj)
{
    struct doubleListNode* nodeIt = obj->front;
    struct doubleListNode* nodeFree = obj->front;
    while (nodeIt != NULL)
    {
        nodeIt = nodeIt->next;
        free(nodeFree);
        nodeFree = nodeIt;
    }
    free(obj);
}


void doubleLsitMove(AllOne* obj, doubleList* targetlistIt, bool isUp)
{

    //数量等于2 直接比较双链表的头尾结点的值
    if (obj->doublelist->count == 2)
    {
        if (obj->doublelist->front->pHashMap->count >= obj->doublelist->rear->pHashMap->count)
        {
            return;
        }
        doubleList* temp = obj->doublelist->front;
        obj->doublelist->front = obj->doublelist->rear;
        obj->doublelist->rear  = temp;
        obj->doublelist->front->prev = NULL;
        obj->doublelist->front->next = obj->doublelist->rear;
        obj->doublelist->rear->prev  = obj->doublelist->front;
        obj->doublelist->rear->next  = NULL;
        return;
    }



    //至少3个结点才开始遍历
    if (isUp)
    {
        //递增 找到当前值 刚好比当前值大的位置
        if (targetlistIt != obj->doublelist->front)
        {
            doubleList* listItPre = targetlistIt->prev;
            //当前节点的cout大于 前一个结点的count值
            if(listItPre->pHashMap->count < targetlistIt->pHashMap->count)
            {
                //循环遍历查找
                while (listItPre != NULL && listItPre->pHashMap->count < targetlistIt->pHashMap->count)
                {
                    listItPre = listItPre->prev;
                }

                if (targetlistIt == obj->doublelist->rear)
                {
                    //特殊处理尾部特殊情况
                    obj->doublelist->rear       = targetlistIt->prev;
                    obj->doublelist->rear->next = NULL;
                }
                



                //插入位置是中间  listItPre > targetlistIt
                if (targetlistIt->prev != NULL)
                    targetlistIt->prev->next = targetlistIt->next;

                if (targetlistIt->next != NULL)
                    targetlistIt->next->prev = targetlistIt->prev;

                if (listItPre == NULL)
                {
                    //插入位置 是头部
                    targetlistIt->next              =    obj->doublelist->front;
                    obj->doublelist->front->prev    = targetlistIt;
                    obj->doublelist->front          = targetlistIt;
                    targetlistIt->prev              = NULL;
                }
                else
                {
                    targetlistIt->next          = listItPre->next;
                    targetlistIt->prev          = listItPre;
                    listItPre->next->prev       = targetlistIt;
                    listItPre->next             = targetlistIt;
                }
            }

        }
    }
    else
    {
        //递减 找到当前值 刚好比当前值小的位置
        if (targetlistIt != obj->doublelist->rear)
        {
            //向后移动
            doubleList* listItNxt = targetlistIt->next;
            //当前节点的cout大于 小于下一个结点的count值
            if (listItNxt->pHashMap->count > targetlistIt->pHashMap->count)
            {
                while (listItNxt != NULL && listItNxt->pHashMap->count > targetlistIt->pHashMap->count)
                {
                    listItNxt = listItNxt->next;
                }

                if (targetlistIt == obj->doublelist->front)
                {
                    //特殊处理头部特殊情况
                    obj->doublelist->front          = targetlistIt->next;
                    obj->doublelist->front->prev    = NULL;
                }

                //插入位置是中间  listItPre < targetlistIt
                if (targetlistIt->prev != NULL)
                    targetlistIt->prev->next = targetlistIt->next;

                if (targetlistIt->next != NULL)
                    targetlistIt->next->prev = targetlistIt->prev;

                if (listItNxt == NULL)
                {
                    //插入到队尾
                    obj->doublelist->rear->next     = targetlistIt;
                    targetlistIt->prev              = obj->doublelist->rear;
                    obj->doublelist->rear           = targetlistIt;
                    targetlistIt->next              = NULL;

                }
                else
                {
                    targetlistIt->prev = listItNxt->prev;
                    targetlistIt->next = listItNxt;
                    listItNxt->prev->next = targetlistIt;
                    
                }
            }
        }
    }
}

void myDobleListRemove(MyQueueList* obj, doubleList* targetlistIt)
{
    if (targetlistIt == obj->front && targetlistIt == obj->rear)
    {
        obj->front = NULL;
        obj->rear = NULL;
    }
    else if (targetlistIt == obj->front)
    {
        obj->front = obj->front->next;
        obj->front->prev = NULL;
    }
    else if (targetlistIt == obj->rear)
    {
        obj->rear = obj->rear->prev;
        obj->rear->next = NULL;
    }
    else
    {
        targetlistIt->prev->next = targetlistIt->next;
        targetlistIt->next->prev = targetlistIt->prev;
    }
    free(targetlistIt);
}

void allOneInc(AllOne* obj, char* key)
{
    hashMapList* hashMapIt = myHashMapGet(obj->hashmap, key);
    if (hashMapIt == NULL)
    {

        doubleList* newlist = (doubleList*)malloc(sizeof(doubleList));
        newlist->next = NULL;
        newlist->prev = NULL;
        //指向对应的hashMap
        //存入hashmap中,保存字符串做key,以及记录次数为1
        //双向指针 从hash表到双链表  从双链表到hash
        newlist->pHashMap = myHashMapPut(obj->hashmap, key, 1);
        newlist->pHashMap->dList = newlist;

        //插入到队尾处
        if (obj->doublelist->rear == NULL)
        {
            obj->doublelist->front = newlist;
            obj->doublelist->rear = newlist;
        }
        else
        {
            obj->doublelist->rear->next = newlist;
            newlist->prev = obj->doublelist->rear;
            obj->doublelist->rear = newlist;
        }
        obj->doublelist->count++;
    }
    else
    {
        hashMapIt->count++; //次数增加
        if (obj->doublelist->count >= 2)
        {
            doubleList* targetlistIt = hashMapIt->dList;
            doubleLsitMove(obj, targetlistIt, true);
        }
    }
}

void allOneDec(AllOne* obj, char* key)
{
    hashMapList* hashMapIt = myHashMapGet(obj->hashmap, key);
    if ((hashMapIt->count - 1) == 0)
    {
        doubleList* targetlistIt = hashMapIt->dList;
        myHashMapRemove(obj->hashmap, key);
        myDobleListRemove(obj->doublelist, targetlistIt);
        obj->doublelist->count--;
    }
    else
    {
        hashMapIt->count--;
        if (obj->doublelist->count >= 2)
        {
            doubleList* targetlistIt = hashMapIt->dList;
            doubleLsitMove(obj, targetlistIt, false);
        }
    }
}

char* allOneGetMaxKey(AllOne* obj)
{
    if (obj->doublelist->front == NULL)
    {
        return  "";
    }
    return obj->doublelist->front->pHashMap->string;
}

char* allOneGetMinKey(AllOne* obj)
{
    if (obj->doublelist->rear == NULL)
    {
        return  "";
    }
    return obj->doublelist->rear->pHashMap->string;
}



void allOneFree(AllOne* obj)
{
    myHashMapFree(obj->hashmap);
    obj->hashmap = NULL;
   myLinkedListFree(obj->doublelist);
   obj->doublelist =NULL;
   free(obj);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

箭头与数字识别系统源码分享

箭头与数字识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

JavaScript 安装库npm报错

今天在编写JavaScript代码时&#xff0c;缺少了包express。 const express require(express); const app express();app.get(/, (req, res) > {res.send(Hello, world!); });app.listen(3000, () > {console.log(Server is running on port 3000); });npm install exp…

【C++指南】C++中nullptr的深入解析

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 引言 一、nullptr的引入背景 二、nullptr的特点 1.类型安全 2.明确的空指针表示 3.函数重载支…

从决策树到GBDT、随机森林

何为决策树 决策树&#xff08;Decision Tree&#xff09;&#xff0c;它是一种以树形数据结构来展示决策规则和分类结果的模型&#xff0c;作为一种归纳学习算法&#xff0c;其重点是将看似无序、杂乱的已知数据&#xff0c;通过某种技术手段将它们转化成可以预测未知数据的树…

3D 模型GLTF、GLB格式文件介绍使用

一、介绍 GLTF&#xff08;GL Transmission Format&#xff09;和 GLB&#xff08;GL Binary&#xff09;是用于在 Web 和各种应用程序中传输和加载 3D 场景和模型的开放标准格式。它们由 Khronos Group 开发&#xff0c;旨在提供一种高效、可扩展且易于使用的 3D 内容格式。以…

Java项目中Linux跑起来

要让一个web项目跑起来首先需要tomat和jdk的包&#xff08;Linux版本&#xff09; 之后可以使用Xftp工具将包传到linux中 可以新建一个java包专门放这些文件 之后将其这些包解压出来 tar -xvf jdk-8u141-linux-x64.tar.gz //换自己的包名使用命令配置自己的环境变量 vim /et…

计算机专业选题推荐-基于python的协同过滤酒店推荐系统

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、协同过滤酒店…

【C++ 11多线程加速计算实操教程】

【C 11多线程加速计算实操教程】 1. 了解线程的基本概念2. 创建线程2.1 启动线程的基本示例&#xff1a;2.2 运行结果 3. 线程加速计算3.1 演示如何使用多个线程计算数组的和&#xff1a;3.2 运行结果3.3 结果分析3.4 拓展学习 4. 互斥量&#xff08;Mutex&#xff09;4.1 演示…

Qt中多语言的操作(以QtCreator为例)

1、首先&#xff0c;我们在代码中与文本相关的且需要支持多语言的地方&#xff0c;用tr来包含多语言key&#xff08;多语言key是我们自己定义的&#xff09;&#xff0c;如下 //举例 QPushButton* btnnew QPushButton(this); btn->move(20,20); btn->resize(100,50); //…

vue.js 展示一个树形结构的数据视图,并禁用其中默认选中的节点

功能描述 展示树形结构&#xff1a; 使用 Element UI 的 <el-tree> 组件展示树形结构数据。数据由 content 数组提供&#xff0c;树形结构包含了嵌套的节点及其子节点。 默认选中节点&#xff1a; 使用 defaultCheckedKeys 属性指定默认选中的节点。这些节点在树形结构渲…

自动换行且带下划线的居中长标题的论文封面一种绘图实现

自动换行且带下划线的居中长标题的论文封面一种绘图实现 引言 在一些学位论文的封面上要求标题带有下划线&#xff0c;但长标题的情况下标题自动换行后下划线就会面临一些问题。 因此&#xff0c;往往需要一些特殊的处理。 在《如何制作自动换行且有定长下划线的论文封面模板…

决策树+随机森林模型实现足球大小球让球预测软件

文章目录 前言一、决策树是什么&#xff1f;二、数据收集与整理1.数据收集2.数据清洗3.特征选择 三、决策树构建3.1绘制训练数据图像3.2 训练决策树模型3.3 依据模型绘制决策树的决策边界3.4 树模型可视化 四、模型预测五、随机森林模型总结 前言 之前搞足球数据分析的时候&…

删除topic提示admin token

这个admin token不是admin的密码&#xff0c;而是如下配置文件中的值&#xff1a; 否则报错&#xff1a; 检查&#xff1a; [rootk1 conf]# pwd /opt/kafka-web/efak-web-3.0.1/conf [rootk1 conf]# grep token system-config.properties # delete kafka topic token efak.t…

教师管理系统小程序+ssm论文源码调试讲解

第二章 开发工具及关键技术介绍 2.1 JAVA技术 Java主要采用CORBA技术和安全模型&#xff0c;可以在互联网应用的数据保护。它还提供了对EJB&#xff08;Enterrise JavaBeans&#xff09;的全面支持&#xff0c;java servlet AI&#xff0c;JS&#xff08;java server ages&…

TCL25届校招测评笔试TAS人才测评题库:高分攻略真题分析

&#x1f31f; 职场新人必看&#xff1a;TCL校招测评全解析 &#x1f31f; 亲爱的小伙伴们&#xff0c;你是否正准备踏入职场&#xff0c;或是对即将到来的校招感到既兴奋又紧张&#xff1f;今天&#xff0c;我将带你深入了解TCL校招中的TAS人才测评&#xff0c;让你在面试前做…

Flutter鸿蒙化环境配置(windows)

Flutter鸿蒙化环境配置&#xff08;windows&#xff09; 参考资料Window配置Flutter的鸿蒙化环境下载配置环境变量HarmonyOS的环境变量配置配置Flutter的环境变量Flutter doctor -v 检测的问题flutter_flutter仓库地址的警告问题Fliutter doctor –v 报错[!] Android Studio (v…

构建数据分析模型,及时回传各系统监控监测数据进行分析反馈响应的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。增…

20 基于STM32的温度、电流、电压检测proteus仿真系统(OLED、DHT11、继电器、电机)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STM32F103C8T6 采用DHT11读取温度、滑动变阻器模拟读取电流、电压。 通过OLED屏幕显示&#xff0c;设置电流阈值为80&#xff0c;电流小阈值为50&#xff0c;电压阈值为60&#xff0c;温度阈值…

虚幻引擎的射线检测/射线追踪

射线检测在 FPS/TPS 游戏中被广泛应用 什么是射线检测? 两个点行成一条线 , 射线检测是从一个起始点发出一条到终点的射线 , 如果射线命中一个游戏对象&#xff0c;就可以获取到对象命中时的 位置、距离、角度、是否命中、骨骼 等非常多的信息 , 这些信息在射击游戏中至关重…

价格便宜又好用的云电脑挑选:ToDesk云电脑 vs 青椒云

云计算技术的成熟使得云电脑因其便捷、灵活和高效而成为日常工作、学习和娱乐的首选工具。而在众多云电脑品牌之中&#xff0c;ToDesk云电脑与青椒云电脑 较为热门 。在此&#xff0c;笔者将围绕价格、性能、用户体验等关键指标对 比 这两款云电脑&#xff0c; 帮助 你们 找到最…