循环链表的实现

2023-05-16

循环链表的实现

说明

  1. 参考资料
    • 传智播客扫地僧的数据结构教学视频
  2. 线性表基本知识
    • 参考
  3. 该实现的说明
    • C语言实现
    • 基于单向链表,参考
    • 实现算法和数据的分离

实现

  • circular_list.h
    #ifndef _CIRCULAR_LIST_H_
    #define _CIRCULAR_LIST_H_
    
    #ifdef __cplusplus
    extern "C"{
    #endif
    
    
    typedef void CIRCULAR_LIST;					// 循环链表类型
    typedef struct CIRCULAR_LIST_NODE			// 循环链表节点类型
    {
    	struct CIRCULAR_LIST_NODE* next;
    }CIRCULAR_LIST_NODE;
    
    
    /* 创建循环链表,返回循环链表的地址 */
    CIRCULAR_LIST* CircularList_Create();
    
    /* 销毁循环链表的空间 */
    void CircularList_Destroy(CIRCULAR_LIST* list);
    
    
    /* 清空循环链表的元素 */
    void CircularList_Clear(CIRCULAR_LIST* list);
    
    
    /* 获取循环链表中元素的个数 */
    int CircularList_Length(CIRCULAR_LIST* list);
    
    
    /* 获取循环链表中下标为pos的元素的地址 */
    CIRCULAR_LIST_NODE* CircularList_Get(CIRCULAR_LIST* list, int pos);
    
    
    /* 在下标为pos的位置插入元素node,返回实际插入的位置 */
    int CircularList_Insert(CIRCULAR_LIST* list, CIRCULAR_LIST_NODE* node, int pos);
    
    
    /* 删除循环链表中下标为pos的节点 */
    CIRCULAR_LIST_NODE* CircularList_Delete(CIRCULAR_LIST* list, int pos);
    
    
    /* 删除循环链表中的节点node */
    CIRCULAR_LIST_NODE* CircularList_DeleteNode(CIRCULAR_LIST* list, CIRCULAR_LIST_NODE* node);
    
    
    /* 重置游标 */
    CIRCULAR_LIST_NODE* CircularList_ResetSlider(CIRCULAR_LIST* list);
    
    
    /* 获取当前游标指向的节点 */
    CIRCULAR_LIST_NODE* CircularList_Current(CIRCULAR_LIST* list);
    
    
    /* 返回当前游标指向的节点,并且游标向前移动一步 */
    CIRCULAR_LIST_NODE* CircularList_SliderNext(CIRCULAR_LIST* list);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    
  • circular_list.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "circular_list.h"
    
    
    typedef struct TAG_CIRCULAR_LIST
    {
    	CIRCULAR_LIST_NODE header;
    	CIRCULAR_LIST_NODE* slider;
    	int length;
    }TAG_CIRCULAR_LIST;
    
    
    /* 创建循环链表,返回循环链表的地址 */
    CIRCULAR_LIST* CircularList_Create()
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    
    	// 申请头节点
    	circular_list = (TAG_CIRCULAR_LIST*)malloc(sizeof(TAG_CIRCULAR_LIST));
    	if(circular_list == NULL)
    	{
    		printf("func CircularList_Create() err: circular_list == NULL\n");
    		return NULL;
    	}
    
    	// 给申请的空间赋一个初值
    	memset(circular_list, 0, sizeof(TAG_CIRCULAR_LIST));
    
    	return circular_list;
    }
    
    
    /* 销毁循环链表的空间 */
    void CircularList_Destroy(CIRCULAR_LIST* list)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    
    	// 检查输入
    	if (list == NULL)
    	{
    		printf("func CircularList_Destroy() err: list == NULL\n");
    		return ;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 避免野指针
    	if (circular_list != NULL)
    	{
    		free(circular_list);
    		circular_list = NULL;
    	}
    		
    	return;
    }
    
    
    /* 清空循环链表的元素 */
    void CircularList_Clear(CIRCULAR_LIST* list)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    
    	// 检查输入
    	if (list == NULL)
    	{
    		printf("func CircularList_Clear() err: list == NULL\n");
    		return;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 清空链表
    	memset(circular_list, 0, sizeof(TAG_CIRCULAR_LIST));
    	
    	return;
    }
    
    
    /* 获取循环链表中元素的个数 */
    int CircularList_Length(CIRCULAR_LIST* list)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    
    	// 检查输入
    	if (list == NULL)
    	{
    		printf("func CircularList_Length() err: list == NULL\n");
    		return -1;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	return circular_list->length;
    }
    
    
    /* 获取循环链表中下标为pos的元素的地址 */
    CIRCULAR_LIST_NODE* CircularList_Get(CIRCULAR_LIST* list, int pos)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    	CIRCULAR_LIST_NODE* current_ptr = NULL;
    	int i = 0;
    
    	// 检查输入
    	if (list == NULL || pos < 0)
    	{
    		printf("func CircularList_Get() err: list == NULL || pos < 0\n");
    		return NULL;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    	
    	// 检查位置合法性
    	if (pos >= circular_list->length)
    	{
    		printf("func CircularList_Get() err: pos >= circular_list->length\n");
    		return NULL;
    	}
    
    	// 将辅助指针移动到pos位置前一个位置
    	current_ptr = (CIRCULAR_LIST_NODE*)circular_list;
    	for (i = 0; i < pos; ++i)
    	{
    		current_ptr = current_ptr->next;
    	}
    
    	// 返回pos位置的地址
    	return current_ptr->next;
    }
    
    
    /* 在下标为pos的位置插入元素node,返回实际插入的位置 */
    int CircularList_Insert(CIRCULAR_LIST* list, CIRCULAR_LIST_NODE* node, int pos)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    	CIRCULAR_LIST_NODE* current_ptr = NULL;
    	CIRCULAR_LIST_NODE* last_ptr = NULL;
    	int i = 0;
    
    	// 检查输入
    	if (list == NULL || node == NULL || pos < 0)
    	{
    		printf("func CircularList_Insert() err: list == NULL || node == NULL || pos < 0\n");
    		return -1;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 容错检查:当pos >= circular_list->length时,采用尾插法
    	if (pos >= circular_list->length)
    	{
    		pos = circular_list->length;
    	}
    
    	// 将辅助指针变量跳转到pos-1位置
    	current_ptr = (CIRCULAR_LIST_NODE*)circular_list;
    	for (i = 0; i < pos; ++i)
    	{
    		current_ptr = current_ptr->next;
    	}
    
    	// 按照单向链表方式直接插入节点
    	node->next = current_ptr->next;
    	current_ptr->next = node;
    	circular_list->length++;
    
    	// 处理特殊情况
    	// 如果此次插入之前循环链表没有节点,需要将链表最后一个节点指向第一个节点
    	if (circular_list->length == 1)
    	{
    		node->next = node;
    	}
    
    	// 如果此次插入之前已经有了节点,并且在0号位置插入,正常插入之后最后一个节点指向的节点变成第2个节点,需要修正
    	if (circular_list->length != 1 && current_ptr == (CIRCULAR_LIST_NODE*)circular_list)
    	{
    		// 获取最后一个节点
    		last_ptr = (CIRCULAR_LIST_NODE*)circular_list;
    		for(i = 0; i < circular_list->length; ++i)
    		{
    			last_ptr = last_ptr->next;
    		}
    		// 将最后一个节点指向第一个节点
    		last_ptr->next = current_ptr->next;
    	}
    
    	return pos;
    }
    
    
    /* 删除循环链表中下标为pos的节点 */
    CIRCULAR_LIST_NODE* CircularList_Delete(CIRCULAR_LIST* list, int pos)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    	CIRCULAR_LIST_NODE* deleted_node = NULL;
    
    	CIRCULAR_LIST_NODE* current_ptr = NULL;
    	CIRCULAR_LIST_NODE* last_ptr = NULL;
    	int i = 0;
    
    	// 检查输入
    	if (list == NULL || pos < 0)
    	{
    		printf("func CircularList_Delete() err: list == NULL || pos < 0\n");
    		return NULL;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 检查pos的合法性
    	if (pos >= circular_list->length)
    	{
    		printf("func CircularList_Delete() err: pos >= circular_list->length\n");
    		return NULL;
    	}
    
    	// 将current_ptr移动到pos-1的位置
    	current_ptr = (CIRCULAR_LIST_NODE*)circular_list;
    	for (i = 0; i < pos; ++i)
    	{
    		current_ptr = current_ptr->next;
    	}
    
    	// 按照单向链表的方式删除节点
    	deleted_node = current_ptr->next;
    	current_ptr->next = deleted_node->next;
    	circular_list->length--;
    
    	// 处理特殊情况
    	// 如果此次删除之后循环链表中将没有节点,那么此次删除之后circular_list->header->next将指向被删除的元素,需要将其置零
    	if (circular_list->length == 0)
    	{
    		current_ptr->next = NULL;
    	}
    
    	// 如果此次删除之后循环链表中还有节点,并且这次删除的是第一个节点,那么删除之后,最后一个节点指向的是一个已经删除的节点,需要修正
    	if (circular_list->length > 0 && current_ptr == (CIRCULAR_LIST_NODE*)circular_list)
    	{
    		// 获取最后一个节点
    		last_ptr = (CIRCULAR_LIST_NODE*)circular_list;
    		for (i = 0; i < circular_list->length; ++i)
    		{
    			last_ptr = last_ptr->next;
    		}
    
    		// 将最后一个节点指向第一个节点
    		last_ptr->next = current_ptr->next;
    	}	
    	return deleted_node;
    }
    
    
    /* 删除循环链表中的节点node */
    CIRCULAR_LIST_NODE* CircularList_DeleteNode(CIRCULAR_LIST* list, CIRCULAR_LIST_NODE* node)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    	int i = 0;
    	CIRCULAR_LIST_NODE* current_ptr = NULL;
    	CIRCULAR_LIST_NODE* deleted_node = NULL;
    	
    	// 参数检查
    	if (list == NULL || node == NULL)
    	{
    		printf("func CircularList_DeleteNode() err: list == NULL || node == NULL\n");
    		return NULL;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 遍历循环链表,找到和node相同的节点就退出循环
    	current_ptr = (CIRCULAR_LIST_NODE*)circular_list;
    	for(i = 0; i < circular_list->length; ++i)
    	{
    		current_ptr = current_ptr->next;
    		if (current_ptr == node)
    		{
    			deleted_node = current_ptr;
    			break;
    		}
    	}
    
    	// 如果查找不到node,报错;找到node之后删除
    	if (i >= circular_list->length)
    	{
    		printf("func CircularList_DeleteNode() err: node is not in circular list\n");
    		return NULL;
    	}
    	else if(i < circular_list->length)
    	{
    		CircularList_Delete(circular_list, i);
    	}
    
    	return deleted_node;
    }
    
    
    /* 重置游标,返回重置之后游标指向的节点 */
    CIRCULAR_LIST_NODE* CircularList_ResetSlider(CIRCULAR_LIST* list)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    
    	// 参数检查
    	if (list == NULL)
    	{
    		printf("func CircularList_ResetSlider() err: list == NULL\n");
    		return NULL;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 重置slider
    	circular_list->slider = circular_list->header.next;
    
    	return circular_list->slider;
    }
    
    
    /* 获取当前游标指向的节点 */
    CIRCULAR_LIST_NODE* CircularList_Current(CIRCULAR_LIST* list)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    
    	// 参数检查
    	if (list == NULL)
    	{
    		printf("func CircularList_Current() err: list == NULL\n");
    		return NULL;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    	
    	// 返回节点,使用者自己保证游标指向的正确性
    	return circular_list->slider;
    }
    
    
    /* 返回当前游标指向的节点,并且游标向前移动一步 */
    CIRCULAR_LIST_NODE* CircularList_SliderNext(CIRCULAR_LIST* list)
    {
    	TAG_CIRCULAR_LIST* circular_list = NULL;
    	CIRCULAR_LIST_NODE* current_ptr = NULL;
    
    	// 参数检查
    	if (list == NULL)
    	{
    		printf("func CircularList_SliderNext() err: list == NULL\n");
    		return NULL;
    	}
    
    	// 将CIRCULAR_LIST_NODE类型的地址转换为TAG_CIRCULAR_LIST类型的地址
    	circular_list = (TAG_CIRCULAR_LIST*)list;
    
    	// 记录当前游标位置
    	current_ptr = circular_list->slider;
    
    	// 如果循环列表没有节点,报错
    	if (circular_list->length == 0)
    	{
    		printf("func CircularList_SliderNext() err: circular_list->length == 0\n");
    		return NULL;
    	}
    	else
    	{
    		circular_list->slider = circular_list->slider->next;
    	}
    	return current_ptr;
    }
    
  • test.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include "circular_list.h"
    
    
    /* 约瑟夫问题:N个人围成一圈,由第一个人从1开始报数,报M的人会被淘汰,然后从后一个人重新开始报数,重复以上过程,求出淘汰的人的顺序 */
    
    
    /* 业务结构,包含一个节点域和一个整形域 */
    typedef struct VALUE
    {
    	CIRCULAR_LIST_NODE* circular_node;
    	int value;
    }VALUE;
    
    
    int main(void)
    {
    	int i = 0;
    	int number_of_people = 16;			// 16个人围成一圈
    	int death_number = 3;				// 报数为3的人死亡
    	VALUE* v = NULL;
    	CIRCULAR_LIST* circular_list = NULL;
    
    	// 创建循环链表
    	circular_list = CircularList_Create();
    	if (circular_list == NULL)
    	{
    		printf("func main(): circular_list == NULL\n");
    		return -1;
    	}
    
    	// 设置随机数种子
    	srand((unsigned int)time(NULL));
    
    	// 随机生成16个人的value
    	for (i = 0; i < number_of_people; ++i)
    	{
    		v = (VALUE*)malloc(sizeof(VALUE));
    		v->circular_node = NULL;
    		v->value = rand()%100;			// 随机生成[0,100)的value值
    
    		// 使用头插法插入循环链表
    		CircularList_Insert(circular_list, (CIRCULAR_LIST_NODE*)v, 0);
    	}
    
    	// 打印循环链表(人围成的圈的顺序)
    	for (i = 0; i < CircularList_Length(circular_list); ++i)
    	{
    		v = (VALUE*)CircularList_Get(circular_list, i);
    		printf("%d ",v->value);
    	}
    	printf("\n");
    
    	// 重置游标,使其指向第一个节点
    	CircularList_ResetSlider(circular_list);
    
    	// 报数,并开始淘汰
    	while (CircularList_Length(circular_list) > 0)
    	{
    		// 报数,开始之后第1个人和第death_number个人中间隔着(death_number - 1)跳
    		for (i = 0; i < (death_number - 1); ++i)
    		{
    			CircularList_SliderNext(circular_list);
    		}
    
    		// 此时游标刚好指向淘汰的人,通过游标得到这个人的信息,并将这个人踢出游戏
    		v = (VALUE*)CircularList_Current(circular_list);
    		CircularList_SliderNext(circular_list);			// 删除之前先将游标移动到下一个开始的位置
    		CircularList_DeleteNode(circular_list, (CIRCULAR_LIST_NODE*)v);
    
    		// 处理淘汰的节点:1. 输出; 2. 销毁空间(循环链表的库不负责销毁)
    		printf("%d\n",v->value);
    		if(v != NULL)
    		{
    			free(v);
    			v = NULL;
    		}
    	}
    
    
    	// 销毁循环链表
    	CircularList_Destroy(circular_list);
    
    	printf("Hello world!\n");
    	return 0;
    }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

循环链表的实现 的相关文章

  • 同步FIFO 两种方法

    RAM 43 空满信号判断 xff0c 两种方法 一 空满标志用指针位置得到 二 空满标志用fifo的中数据的计数得到 一 当写指针超过读指针一圈 xff0c 写满 xff1b 写指针等于读指针 xff0c 读空 96 timescale
  • linux内核串口日志抓取-minicom工具使用方法

    linux抓串口日志 抓串口日志方式minicom保存串口日志log抓取主板串口日志minicom man手册 抓串口日志方式 1 xff09 问题机上 xff0c 找到串口设备 xff0c 比如 dev ttyAMA 0 1 2 3 st
  • 二叉树(七):二叉树的高度与平衡二叉树

    一 二叉树的深度与高度 1 二叉树的深度 对于二叉树中的某个节点 xff0c 其深度是从根节点到该节点的最长简单路径所包含的节点个数 xff0c 是从上面向下面数的 因此访问某个节点的深度要使用先序遍历 2 二叉树的高度 对于二叉树中的某个
  • Python --语法自纠

    文章目录 1 输入2 数据类型转换 xff0c 字符串3 字典 xff0c 列表 xff0c 元组4 语法0 错题 1 输入 输入eval作用一次输入一个或多个 map print format m n format输出 2 数据类型转换
  • 强化学习算法复现(六):DoubleDQN_gym倒立摆

    建立RL brain py span class token keyword import span torch span class token keyword import span torch span class token pun
  • Android的控件绑定----ViewBinding

    在Android开发中 xff0c 控件的绑定是开发者无法绕开的一道程序 是Android开发中最原始 xff0c 也是最基础的一种获取View的方法 在一个复杂布局的页面时 xff0c 我们要一个个控件去调用findViewById方法去
  • C++ OpenCV CV_***未声明的标识符的解决办法

    1 OpenCV cvtColor CV BGR2GRAY未声明的标识符的解决办法 加上这个引用即可 include lt opencv2 imgproc types c h gt 2 opencv里面CV FOURCC找不到标识符 CV
  • 多线程-生产者和消费者模式

    1 简单实现多线程 多线程是多任务处理的一种特殊形式 xff0c 多线程处理允许让一个进程中同时运行两个或两个以上的线程 这样的话 xff0c 能更加充分发挥计算机的性能 xff0c 并高效完成用户的任务 多线程实现的三步骤 xff1a 第
  • HTML网页注册图片

    lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt lt title gt lt style type 61 34 t
  • [WAX云钱包】解决Cloudflare通过SSL指纹识别实现的反爬虫机制

    WAX云钱包 在之前的多篇文章中 xff0c 我们使用 Python 43 Selenium 来实现WAX链游脚本 xff0c 主要是因为很多玩家一开始都是用WAX云钱包注册的账号 xff0c 而WAX云钱包的私钥托管在云端 xff0c 我
  • 小狼毫[rime_win][眀月拼音]简单配置方法

    小狼毫 rime win 朙月拼音 简单配置方法 我自己的配置文件 当配置后 需要重新部署后设置才能生效 需要修改的文件 需要修改 增加的文件均在用户文件夹下 用户文件夹可以通过右键输入法状态栏的图标后点击用户文件夹到达 修改 增加的文件名
  • 生产者消费者模式(c++)

    什么是生产者消费者模式 xff1f 想象一下 xff0c 你早上起来肚子快饿扁了 xff0c 去包子铺买包子 xff0c 包子铺有三个人在做包子 xff08 也可以是一个 xff09 xff0c 这些人就是生产者 xff0c 你作为买包子的
  • go语言interface转string、bool、int

    在go语言中interface转string可以直接使用fmt提供的fmt函数 xff0c 而转bool和int则是在string的基础上来进行转换 xff0c 详见如下代码 func Get f string value interfac
  • centos7中启动juoyter notebook后,复制链接无法打开网页

    centos7中启动juoyter notebook后 xff0c 复制链接无法打开网页 xff0c 一直停留在如下界面 xff1a 解决办法 xff1a 这需要在Linux浏览器中打开 在windows中无法打开 xff0c 若没有安装l
  • 数据结构——BF, KMP

    文章目录 1 串的基本操作2 串的BF模式 朴素的模式匹配 暴力匹配 定位操作 3 串的KMP模式匹配 定位操作 1 规则 xff1a 2 举例 xff1a 3 采用以空间换时间策略 xff0c 操作方法如下 xff1a 4 操作举例 xf
  • linux如何在界面和终端的不同模式下运行pyspark?

    一 xff0c 界面打开 1 直接输入jupyter notebook后打开界面 查看运行模式 xff1a 输入sc master 若输出为 xff1a local xff0c 则表示它是在本地模式下运行 2 xff0c 如何使用jupyt
  • 官网下载eclipse太慢解决办法及jdk版本要求

    1 Eclipse 4 6 Neon 需要JDK1 8版本 2 Eclipse 4 5 Mars 需要JDK1 7及以上版本 3 Eclipse 4 4 Luna 需要JDK1 7及以上版本 4 Eclipse 4 3 Kepler 需要J
  • Ubuntu中Pycharm快捷方式只能以sudo sh pycharm.sh运行,双击快捷方式没反应怎么办?

    创建pycharm快捷方式的博客文章很多 xff0c 我找了很久才解决我的问题 xff0c 这里主要参考这篇 xff1a 链接 link 主要问题 双击pycharm快捷方式没反应 xff0c 只能在终端中用sudo sh pycharm
  • Gazebo上帝视角里程计 get_model_state 绝对里程计

    Gazebo model states Gazebo有一个服务 gazebo get model state 和一个话题 gazebo model states 来反馈model的状态 服务 gazebo get model state 话
  • 【GaussDB数据库----连接】

    1 确认连接信息 客户端工具通过CN连接数据库 因此连接前 xff0c 需获取CN所在服务器的IP地址及CN的端口号信息 客户端工具可以通过任何一个CN连接数据库 以操作系统用户omm登录安装有MPPDB服务的任一主机 执行source B

随机推荐

  • 天干地支(出生年月的转换)

    十 天干 xff1a 甲 xff08 ji xff09 乙 xff08 y xff09 丙 xff08 b ng xff09 丁 xff08 d ng xff09 戊 xff08 w xff09 己 xff08 j xff09 庚 xff0
  • http转https后资源加载失败的解决方案

    之前没给域名加SSL证书的时候 xff0c 项目好好的 xff0c icon图标还有 xff0c 给域名了SSL证书后 xff0c icon图标就不在了 原因就是因为项目本身采用http的资源文件 xff0c 换成https后就不解析这些资
  • Docker 安装 Redis + Spring Boot 整合 Redis

    Docker安装Redis 一 启动docker容器 systemctl start docker 二 拉取redis镜像 docker pull redis 三 端口映射 docker run name redis p 6379 6379
  • 如何保证缓存与数据库数据一致性

    redis系列之数据库与缓存数据一致性解决方案 重点文章 xff1a https www cnblogs com cxxjohnson p 8519616 html 你只要用缓存 xff0c 就可能会涉及到缓存与数据库双存储双写 xff0c
  • 2020年:maven配置最新阿里云镜像,以及在IDEA中的设置

    记得当初学习Maven的时候 xff0c 由国外的中央仓库切换为阿里云镜像之后 xff0c 用起来是辣么地丝滑 不过最近一段时间 xff0c Maven却总是出现一些问题 xff0c 本地库里也总是出现一些 lastUpdated文件 xf
  • Node.js—— MySQL(第三方API ),web开发模式

    文章目录 0 目标1 数据库 xff08 数据库管理系统 xff09 2 MySQL3 SQL语句1 基本语句2 js 操作数据库中的查询 xff0c 增加 xff0c 更新 xff08 改 xff09 xff0c 删除 3 MYSQL操作
  • 实现生产者消费者模式的三种方式

    什么是生产者消费者模式 简单来说 xff0c 生产者消费者模式就是缓冲区 那么这么做有两个好处 xff0c 一个是解耦 xff0c 第二个是平衡生产能力和消费能力的差 xff0c 因为生产者和消费者的速度是不一样的 xff0c 有了这个缓冲
  • Go语言Windows10安装和环境配置详细步骤

    文章目录 前言一 下载Go安装包 xff1f 二 安装步骤1 安装2 验证是否安装成功 环境配置1 环境配置准备1 配置步骤 前言 提示 xff1a 我用的是windows10系统 xff1a 例如 xff1a Go安装包下载和在windo
  • C语言中scanf、gets、fgets,C++中cin、getline读取字符串的效率比较

    转自 xff1a https blog csdn net richenyunqi article details 89203826 可以使用C语言中scanf gets fgets xff0c C 43 43 中cin getline函数读
  • Android.mk和Android.bp的语句转换

    编译不同类型的模块 编译成 Native 动态库 Android mk include BUILD SHARED LIBRARY Android bp cc library shared 编译成 Native 静态库 Android mk
  • 学习c/c++ 推荐学习什么书籍?

    学习编程包含以下几个重要方面 xff1a 了解语言的语法 知道那些特性可以使用和何时使用 写出可读性好的代码 编译器可以理解 xff0c 但是下一个人是否可以阅读呢 xff1f 在一个更高层次设计结构良好的程序 为了学习一门语言 xff0c
  • 深入理解 http 反向代理(nginx)

    要理解什么是 反向代理 reverse proxy 自然你得先知道什么是 正向代理 forward proxy 另外需要说的是 一般提到反向代理 通常是指 http 反向代理 但反向代理的范围可以更大 比如 tcp 反向代理 在这里 不打算
  • 01-【Royal TSX】Mac上最好用的SSH工具Royal TSX使用教程

    参考文章 xff1a https www jianshu com p 0206980f529e
  • 数据结构:线性结构(C语言)

    文章目录 线性结构线性表什么是线性表线性表的抽象类型描述线性表的实现 广义表广义表定义多重链表 堆栈什么是堆栈堆栈的抽象数据类型描述堆栈的顺序存储实现堆栈的链式存储实现堆栈的应用 队列什么是队列队列的抽象数据类型描述队列的顺序存储实现队列的
  • 树(C语言)

    文章目录 树树的定义树的一些基本术语树的表示 树 树的定义 树 xff08 Tree xff09 xff1a n n 0
  • 堆(C语言)

    文章目录 堆 heap 什么是堆最小堆的操作操作集的实现 C语言 堆 heap 什么是堆 定义 堆 heap 是计算机科学中一类特殊的数据结构的统称 堆通常是一个可以被看做一棵树的数组对象 性质 结构性 xff1a 用数组表示的完全二叉树
  • VS2017中fopen等函数报错解决方法

    文章目录 VS2017中fopen 函数报错解决方法问题解决方法 VS2017中fopen 函数报错解决方法 问题 用VS2017写C语言代码的时候 xff0c 代码中使用了fopen 函数 xff0c 调试之后报错如下 xff1a err
  • 定位,浮动,BFC

    文章目录 1 xff0c 定位1 margin 与 padding 区别 xff1a 2 定位 xff1a 2 xff0c 元素分类 xff0c 浮动 xff0c BFC1 1 常见块级元素 xff1a 1 2 常见行内元素 xff1a 1
  • 表排序

    文章目录 表排序 表排序 思想 当待排数组中的元素不是简简单单的整数 xff0c 而是复杂的结构体 xff0c 那么移动元素所花费的时间就不能忽略不计了 xff0c 这时候我们要减少元素之间移动的次数了 表排序就是这么一个排序 xff0c
  • 循环链表的实现

    循环链表的实现 说明 参考资料 传智播客扫地僧的数据结构教学视频 线性表基本知识 参考 该实现的说明 C语言实现基于单向链表 xff0c 参考实现算法和数据的分离 实现 circular list h span class token ma