双链表——“数据结构与算法”

2023-05-16

各位CSDN的uu们你们好呀,今天,小雅兰又回来了,到了好久没有更新的数据结构与算法专栏,最近确实发现自己有很多不足,需要学习的内容也有很多,所以之后更新文章可能不会像之前那种一天一篇或者一天两篇啦,话不多说,下面,让我们进入双链表的世界吧


 之前小雅兰写过单链表的文章:https://xiaoyalan.blog.csdn.net/article/details/130353520?spm=1001.2014.3001.5502

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

 

 这八种结构分别为:单向带头循环链表、单向带头非循环链表、单向不带头循环链表、单向不带头非循环链表、双向带头循环链表、双向带头非循环链表、双向不带头循环链表、双向不带头非循环链表

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:

单向不带头非循环链表和双向带头循环链表

  • 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  • 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了,后面我们代码实现了就知道了。  

下面,我们开始用代码和图来实现一下双向带头循环链表!!!

在后续函数中,有很多函数都需要这样一个功能:创建一个新节点

那么,我们把此功能单独封装成一个函数:

//创建一个新节点
LTNode* BuyLTNode(LTDataType x)
{
	LTNode* newnode = ((LTNode*)malloc(sizeof(LTNode)));
	if (newnode == NULL)
	{
		printf("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

双链表的初始化:

//双链表的初始化
LTNode* LTInit()
{
	//哨兵位的头节点
	LTNode* phead = BuyLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

 尾插:

 

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* tail = phead->prev;
	//malloc一个新节点
	LTNode* newnode = BuyLTNode(x);
	//让tail的下一个结点指向newnode,链接起来
	tail->next = newnode;
	//newnode的前一个结点指向tail
	newnode->prev = tail;
	//newnode的下一个结点指向头,形成循环
	newnode->next = phead;
	//phead的上一个结点指向newnode
	phead->prev = newnode;
}

头插:

 

//头插
//插在哨兵位的头节点的后面
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = BuyLTNode(x);
	LTNode* first = phead->next;
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}

当然,这样的代码可读性是非常高的,可是,有些人就不喜欢定义那么多指针,然后就还有另外一种写法:

//头插
//插在哨兵位的头节点的后面
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = BuyLTNode(x);
	newnode->next = phead->next;
	phead->next->prev = newnode;
	phead->next = newnode;
	newnode->prev = phead;
}

 但是这样的代码,可读性就显得不是那么的高,所以尽量不要使用这种写法

不是说你写代码多定义了几个指针就说你写的代码没有那些没有定义什么指针的代码差,关键得看可读性!!!

双链表的打印:

//双链表的打印
void LTPrint(LTNode* phead)
{
	assert(phead);
	printf("guard<--->");
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d<--->", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

 下面,让我们来验证一下头插和尾插的功能

void TestDoubleList1()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPushBack(plist, 5);
	LTPrint(plist);
	LTPushFront(plist, 6);
	LTPushFront(plist, 7);
	LTPushFront(plist, 8);
	LTPushFront(plist, 9);
	LTPushFront(plist, 10);
	LTPrint(plist);
}
int main()
{
	TestDoubleList1();
	return 0;
}

 尾删:

 首先要判断此链表是否为空:

bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}
//尾删
void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;
	free(tail);
	tailPrev->next = phead;
	phead->prev = tailPrev;
}

头删:

 

 

bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}
//头删
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTNode* first = phead->next;
	LTNode* second = first->next;
	phead->next = second;
	second->prev = phead;
	free(first);

}

头删也有另外一种写法,和上面阐述的一样,也是可以不用定义这么多指针,但是代码的可读性差一些

bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}
//头删
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTNode* next = phead->next;
	phead->next = next->next;
	next->next->prev = phead;
	free(next);
}

下面,让我们来验证一下头删和尾删的功能

void TestDoubleList2()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPushBack(plist, 5);
	LTPrint(plist);
	LTPushFront(plist, 6);
	LTPushFront(plist, 7);
	LTPushFront(plist, 8);
	LTPushFront(plist, 9);
	LTPushFront(plist, 10);
	LTPrint(plist);
	LTPopBack(plist);
	LTPopBack(plist);
	LTPrint(plist);
	LTPopFront(plist);
	LTPopFront(plist);
	LTPrint(plist);
}
int main()
{
	TestDoubleList2();
	return 0;
}

在双链表里面查找:

//在双链表里面查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
}

在pos位置之前插入值: 

 

//在pos位置之前插入
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);
	LTNode* prev = pos->prev;
	LTNode* newnode = BuyLTNode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}

一般查找和在pos位置之前插入值是搭配使用的!!!

下面,让我们来测试一下此功能:

void TestDoubleList3()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPushBack(plist, 5);
	LTPrint(plist);
	LTPushFront(plist, 6);
	LTPushFront(plist, 7);
	LTPushFront(plist, 8);
	LTPushFront(plist, 9);
	LTPushFront(plist, 10);
	LTPrint(plist);
	LTPopBack(plist);
	LTPopBack(plist);
	LTPrint(plist);
	LTPopFront(plist);
	LTPopFront(plist);
	LTPrint(plist);
	LTNode* pos = LTFind(plist, 3);
	if (pos != NULL)
	{
		LTInsert(pos, 30);
	}
	LTPrint(plist);

}
int main()
{
	TestDoubleList3();
	return 0;
}

 在pos位置之前插入值这个功能,可以很好地解决之前头插和尾插的功能,头插和尾插可以直接复用此代码:

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
	LTInsert(phead->next, x);
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTInsert(phead, x);
}

删除pos位置的值: 

 

//删除pos位置的值
void LTErase(LTNode* pos)
{
	assert(pos);
	LTNode* posPrev = pos->prev;
	LTNode* posNext = pos->next;
	posPrev->next = posNext;
	posNext->prev = posPrev;
	free(pos);
}

验证一下该删除功能:

void TestDoubleList4()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPushBack(plist, 5);
	LTPrint(plist);
	LTPushFront(plist, 6);
	LTPushFront(plist, 7);
	LTPushFront(plist, 8);
	LTPushFront(plist, 9);
	LTPushFront(plist, 10);
	LTPrint(plist);
	LTPopBack(plist);
	LTPopBack(plist);
	LTPrint(plist);
	LTPopFront(plist);
	LTPopFront(plist);
	LTPrint(plist);
	LTNode* pos = LTFind(plist, 3);
	if (pos != NULL)
	{
		LTInsert(pos, 30);
	}
	LTPrint(plist);
	pos = LTFind(plist, 1);
	if (pos != NULL)
	{
		LTErase(pos);
	}
	LTPrint(plist);
}
int main()
{
	TestDoubleList4();
	return 0;
}

 

这个功能也很神奇,删除pos位置的值,之前我们写的头删和尾删一样可以复用此代码的功能

//尾删
void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTErase(phead->prev);
}
//头删
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTErase(phead->next);
}

 双链表的销毁:

//双链表的销毁
void LTDestroy(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

如果不销毁双链表,就会有内存泄漏的问题!!!


源代码如下:

List.h的内容:

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
	struct ListNode* prev;
	struct ListNode* next;
	LTDataType data;
}LTNode;
//双链表的初始化
LTNode* LTInit();
//双链表的打印
void LTPrint(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头删
void LTPopFront(LTNode* phead);
//在双链表里面查找
LTNode* LTFind(LTNode* phead, LTDataType x);
//在pos位置之前插入
void LTInsert(LTNode* pos, LTDataType x);
//删除pos位置的值
void LTErase(LTNode* pos);
//双链表的销毁
void LTDestroy(LTNode* phead);

List.c的内容:

#include"List.h"
//创建一个新节点
LTNode* BuyLTNode(LTDataType x)
{
	LTNode* newnode = ((LTNode*)malloc(sizeof(LTNode)));
	if (newnode == NULL)
	{
		printf("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}
//双链表的初始化
LTNode* LTInit()
{
	//哨兵位的头节点
	LTNode* phead = BuyLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}
//双链表的打印
void LTPrint(LTNode* phead)
{
	assert(phead);
	printf("guard<--->");
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d<--->", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* tail = phead->prev;
	//malloc一个新节点
	LTNode* newnode = BuyLTNode(x);
	//让tail的下一个结点指向newnode,链接起来
	tail->next = newnode;
	//newnode的前一个结点指向tail
	newnode->prev = tail;
	//newnode的下一个结点指向头,形成循环
	newnode->next = phead;
	//phead的上一个结点指向newnode
	phead->prev = newnode;
}
//头插
//插在哨兵位的头节点的后面
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = BuyLTNode(x);
	LTNode* first = phead->next;
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}
头插
插在哨兵位的头节点的后面
//void LTPushFront(LTNode* phead, LTDataType x)
//{
//	assert(phead);
//	LTNode* newnode = BuyLTNode(x);
//	newnode->next = phead->next;
//	phead->next->prev = newnode;
//	phead->next = newnode;
//	newnode->prev = phead;
//}
头插
//void LTPushFront(LTNode* phead, LTDataType x)
//{
//	LTInsert(phead->next, x);
//}
尾插
//void LTPushBack(LTNode* phead, LTDataType x)
//{
//	assert(phead);
//	LTInsert(phead, x);
//}
bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}
//尾删
void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;
	free(tail);
	tailPrev->next = phead;
	phead->prev = tailPrev;
}
头删
//void LTPopFront(LTNode* phead)
//{
//	assert(phead);
//	assert(!LTEmpty(phead));
//	LTNode* next = phead->next;
//	phead->next = next->next;
//	next->next->prev = phead;
//	free(next);
//}
//头删
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTNode* first = phead->next;
	LTNode* second = first->next;
	phead->next = second;
	second->prev = phead;
	free(first);
}
尾删
//void LTPopBack(LTNode* phead)
//{
//	assert(phead);
//	assert(!LTEmpty(phead));
//	LTErase(phead->prev);
//}
头删
//void LTPopFront(LTNode* phead)
//{
//	assert(phead);
//	assert(!LTEmpty(phead));
//	LTErase(phead->next);
//}
//在双链表里面查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
}
//在pos位置之前插入
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);
	LTNode* prev = pos->prev;
	LTNode* newnode = BuyLTNode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}
//删除pos位置的值
void LTErase(LTNode* pos)
{
	assert(pos);
	LTNode* posPrev = pos->prev;
	LTNode* posNext = pos->next;
	posPrev->next = posNext;
	posNext->prev = posPrev;
	free(pos);
}
//双链表的销毁
void LTDestroy(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

好啦,小雅兰今天的学习内容就到这里啦,还要继续加油噢!!!

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

双链表——“数据结构与算法” 的相关文章

  • ubuntu18.04安装ros及解决rosdep update失败问题

    1 安装ros 转自 https blog csdn net qq 44830040 article details 106049992 ops request misc 61 257B 2522request 255Fid 2522 25
  • 球机是枪机和云台机的结合体

    1 枪机是监控类CCD摄像机中一种 枪机外观长方体 xff0c 前面是C CS镜头接口 xff0c 枪机不包含镜头 所谓的枪机主要从外型 镜头安装接口上区分 2 监控类摄像机主要有 xff1a 枪机 小半球 大半球 一体机 球机几个类别 枪
  • ROS学习笔记-1

    一 ROS简介 ROS全称Robot Operating System 机器人操作系统 ROS是适用于机器人的开源元操作系统 ROS集成了大量的工具 xff0c 库 xff0c 协议 xff0c 提供类似OS所提供的功能 xff0c 简化对
  • C语言指针详解(1)

    指针详解 之前我说过一篇关于指针在C语言中的基本使用 xff0c 这次我再来细讲一下指针的其他内容 目录 一 指针详解 1 指针定义 2 指针类型 3 野指针 4 如何规避野指针 xff1f 1 指针定义 指针理解的2个要点 xff1a 1
  • C语言结构体详解 (2) 结构体内存对齐,默认对齐数

    前言 上次 xff0c 我讲到了关于结构体的基本使用 xff0c 大家若感兴趣的话看一看我之前写的一篇结构体博客 xff0c 里面记载了我对于结构体的创建 初始化 嵌套结构体 结构体的访问访问方式和结构体传参方式等知识的见解 xff0c C
  • C语言——十进制转换十六进制

    请编写程序 xff0c 输入十进制数 xff0c 输出对应的十六进制数 输入格式 十进制非负整数 输出格式 对应的十六进制非负整数 要求 xff1a 十六进制数中的字母均为大写形式 输入样哩 5050 输出样例 13BA 代码输入 xff1
  • 如何编写头文件及使用Makefile

    头文件中应该写什么 xff1a 头文件可能会被任意源文件包含 xff0c 意味着头文件中的内容可能会在多个目标文件中存在 xff0c 要保证合并时不要冲突 重点 xff1a 头文件只编写声明语句 xff0c 不能有定义语句 全局变量声明 函
  • 剖析Linux内存中的/proc/meminfo参数

    PROC MEMINFO之谜 proc meminfo是了解Linux系统内存使用状况的主要接口 xff0c 我们最常用的 free vmstat 等命令就是通过它获取数据的 xff0c proc meminfo所包含的信息比 free 等
  • 看完秒懂:Linux DMA mapping机制分析

    说明 xff1a Kernel版本 xff1a 4 14ARM64处理器 xff0c Contex A53 xff0c 双核使用工具 xff1a Source Insight 3 5 xff0c Visio 1 概述 DMA xff08 D
  • linux网络编程-多进程实现TCP并发服务器

    服务端流程步骤 socket函数创建监听套接字lfd bind函数将监听套接字绑定ip和端口 listen函数设置服务器为被动监听状态 xff0c 同时创建一条未完成连接队列 xff08 没走完tcp三次握手流程的连接 xff09 xff0
  • Linux内核中断下半部工作队列(work queue)

    工作队列work queue 工作队列 xff08 work queue xff09 是中断下半部的一种实现机制 xff0c 主要用于耗时任务处理 xff0c 由内核线程代表进程执行 工作队列运行于进程上下文 xff0c 因此允许阻塞 运行
  • 手把手带你部署Ceph集群

    前言 xff1a Ceph作为开源的分布式文件系统 xff0c 可以轻松地将存储容量扩展到PB以上并拥有不错的性能 Ceph提供对象存储 块存储和文件系统三种存储方式 xff0c 如果不想花时间安装ceph xff0c 可以通过ceph d
  • Linux 内核安全增强—— stack canary

    一 背景知识 aarch64的函数栈 1 栈生长方向与push pop操作 栈是一种运算受限的线性表 入栈的一端为栈顶 xff0c 另一端则为栈底 其生长方向和操作顺序理论上没有限定 而在aarch64平台上 栈是向低地址方向增长的 STA
  • Linux下Makefile的简单编写与使用

    Makefile 一个工程文件中的源文件可能有很多 xff0c 并且不同的功能 模块等都放在不同的目录中 xff0c 常规的编译已经不能高效化的处理这样的问题 xff0c 而Makefile就是为解决这一问题而来 Makefile一旦写好
  • STM32 USART 串口DMA收发注意事项

    正常情况这里不介绍 目录 1 低波特率情况 xff0c 接收信号可能会出现干扰 2 波特率300时 xff0c DMA接收无法工作 3 波特率1200时DMA发送 4 具体现象如下 环境 xff1a 主频72M STM32F103C8 注意
  • STM32学习笔记———几种简单传感器的数据读取

    引言 传感器正如计算机的眼睛 从广义上讲 xff0c 传感器就是一种能感知外界信息 xff0c 并将这些信息按照一定规律转换成可用的电信号或其他形式的输出信号的装置 xff0c 达到对信息的存储 xff0c 传输 xff0c 控制的目的 本
  • 基于STM32F103C8T6的USART1串口的中断接收

    一 串口介绍 二 项目所需硬件 1 USB转串口模块 三 项目代码 一 串口介绍 USART Universal Synchronous Asynchronous Receiver Transmitter 通用同步 异步串行接收 发送器 U
  • 第5讲—寄存器编程

    编程方式两种 xff0c 一种是寄存器编程 xff0c 一种是函数库编程 什么是寄存器 stm32芯片 61 ARM内核生产Cortex内核 43 st公司 xff08 在内核基础上 xff09 开发stm32 寄存器是用来地址操作的 寄存
  • C语言运行HTTP代码示例

    include lt iostream gt include lt algorithm gt include lt cstring gt include 34 curl curl h 34 usingnamespace std static
  • 在Linux上实现HTTP请求

    在Linux上实现HTTP请求是一种非常有用的技能 xff0c 有时候我们需要从Web服务器获取数据 xff0c 而不是使用浏览器发起网络调用 HTTP是一种常用的网络协议 xff0c 可以用于在Linux上实现HTTP请求 要在Linux

随机推荐

  • Linux下设置堆栈系统参数

    Linux系统下有几个与堆栈相关的系统参数 xff1a 1 ulimit s xff1a 此参数用于限制进程的堆栈大小 可以使用该命令来查看和更改进程的堆栈大小限制 2 proc sys kernel stack protect xff1a
  • Leetcode每日一题——“消失的数字”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰又开新专栏了 xff0c 以后会在Leetcode上面进行刷题 xff0c 尽量每天写一道 xff0c 请大家监督我 xff01 xff01 xff01 好啦 xff0c 让
  • Leetcode每日一题——“轮转数组”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰的内容是轮转数组 xff0c 下面 xff0c 让我们进入轮转数组的世界吧 小雅兰之前其实就已经写过了字符串旋转的问题了 xff1a C语言刷题 xff08 7 xff09
  • Python一行命令搭建HTTP服务器并外网访问【内网穿透】

    文章目录 1 前言2 本地http服务器搭建2 1 Python的安装和设置2 2 Python服务器设置和测试 3 cpolar的安装和注册3 1 Cpolar云端设置3 2 Cpolar本地设置 4 公网访问测试5 结语 转载自远程内网
  • 顺序表(更新版)——“数据结构与算法”

    各位CSDN的uu们你们好呀 xff0c 今天小雅兰又来更新新专栏啦 xff0c 其实之前我就已经写过了顺序表的内容 xff0c 只是之前的内容不是最新版的顺序表 xff0c 现在 xff0c 我来更新一下最新版的顺序表 xff0c 下面
  • Leetcode每日一题——“移除元素”

    各位CSDN的uu们你们好呀 xff0c 小雅兰又来啦 xff0c 今天 xff0c 小雅兰的内容是移除元素 xff0c 下面 xff0c 让我们进入Leetcode的世界吧 说明 为什么返回数值是整数 xff0c 但输出的答案是数组呢 请
  • Leetcode每日一题——“回文数”

    各位CSDN的uu们 xff0c 你们好呀 xff0c 今天小雅兰又来刷力扣啦 xff0c 今天的题目是回文数 xff0c 下面 xff0c 让我们进入回文数的世界吧 示例 1 xff1a 输入 xff1a x 61 121 输出 xff1
  • 【社区图书馆】《新程序员005:开源深度指南 & 新金融背后的科技力量》

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰来给大家推荐一本书 xff0c 此书的书名为新程序员005 xff1a 开源深度指南 amp 新金融背后的科技力量 xff0c 为什么小雅兰今天要给大家推荐这样一本书呢 xf
  • Nodejs快速搭建简单的HTTP服务器,并发布公网远程访问

    文章目录 前言1 安装Node js环境2 创建node js服务3 访问node js 服务4 内网穿透4 1 安装配置cpolar内网穿透4 2 创建隧道映射本地端口 5 固定公网地址 转载自内网穿透工具的文章 xff1a 使用Node
  • Leetcode每日一题——“合并两个有序数组”

    各位CSDN的uu们你们好呀 xff0c 又到小雅兰的愉快题解时候啦 xff0c 今天 xff0c 我们的题目内容是合并两个有序数组 xff0c 下面 xff0c 让我们进入合并两个有序数组的世界吧 示例 1 xff1a 输入 xff1a
  • Leetcode每日一题——“链表的中间结点”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰愉快的刷题内容是链表的中间结点 嘿嘿 xff0c 小雅兰的单链表还在偷懒ing xff0c 一直没有更新 xff0c 最近应该会更新出来 下面 xff0c 就让我们进入链表的
  • VRPN-体验

    VRPN简介 VRPN提供封装在库里的一套类 xff0c 在VR系统中 xff0c 用来为应用程序和物理外设提供网络传输接口 详细点击这里 VRPN源码获取 git clone https github com vrpn vrpn git
  • 单链表——“数据结构与算法”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰的内容终于是我们心心念念的单链表啦 xff0c 这一块呢 xff0c 是一个很重要的部分 xff0c 也是一个对目前的我来说 xff0c 比较困难的部分 xff0c 下面 x
  • springboot服务端接口外网远程调试,并实现HTTP服务监听【内网穿透】

    文章目录 前言1 本地环境搭建1 1 环境参数1 2 搭建springboot服务项目 2 内网穿透2 1 安装配置cpolar内网穿透2 1 1 windows系统2 1 2 linux系统 2 2 创建隧道映射本地端口2 3 测试公网地
  • MCSM面板一键搭建我的世界服务器-外网远程联机【内网穿透】

    文章目录 前言1 Mcsmanager安装2 创建Minecraft服务器3 本地测试联机4 内网穿透4 1 安装cpolar内网穿透4 2 创建隧道映射内网端口 5 远程联机测试6 配置固定远程联机端口地址6 1 保留一个固定TCP地址6
  • 初识MySQL数据库——“MySQL数据库”

    各位CSDN的uu们你们好呀 xff0c 小雅兰好久没有更文啦 xff0c 确实是心有余而力不足 xff0c 最近学习的内容太难了 xff0c 这篇博客又是小雅兰的新专栏啦 xff0c 主要介绍的是一些MySQL数据库的知识点 xff0c
  • Windows10本地搭建网站教程【内网穿透】

    文章目录 概述1 搭建一个静态Web站点2 本地浏览测试站点是否正常3 本地站点发布公网可访问3 1 安装cpolar内网穿透3 2 创建隧道映射公网地址3 3 获取公网URL地址 4 公网远程访问内网web站点5 配置固定二级子域名5 1
  • MySQL环境搭建——“MySQL数据库”

    各位CSDN的uu们你们好呀 xff0c 小雅兰又来啦 xff0c 好久没有更文啦 xff0c 今天继续 xff01 xff01 xff01 今天小雅兰的内容是MySQL环境搭建 xff0c 下面 xff0c 让我们进入MySQL数据库的世
  • 在树莓派上搭建WordPress博客网站【内网穿透】

    文章目录 概述安装 PHP安装MySQL数据库安装 Wordpress设置您的 WordPress 数据库设置 MySQL MariaDB创建 WordPress 数据库 WordPress configuration将WordPress站
  • 双链表——“数据结构与算法”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰又回来了 xff0c 到了好久没有更新的数据结构与算法专栏 xff0c 最近确实发现自己有很多不足 xff0c 需要学习的内容也有很多 xff0c 所以之后更新文章可能不会像