C语言实现链表--数据结构

news2024/11/20 7:17:20

在这里插入图片描述

  • 魔王的介绍:😶‍🌫️一名双非本科大一小白。
  • 魔王的目标:🤯努力赶上周围卷王的脚步。
  • 魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥
    请添加图片描述
    ❤️‍🔥大魔王与你分享:很喜欢宫崎骏说的一句话:“不要轻易去依赖一个人,它会成为你的习惯当分别来临,你失去的不是某个人而是你精神的支柱,无论何时何地,都要学会独立行走,它会让你走得更坦然些。”

文章目录

  • 一、前言
  • 二、链表实现
    • 1、创建结构体类型
    • 2、创建结点
    • 3、打印单链表
    • 4、单链表尾插
    • 5、单链表头插
    • 6、单链表尾删
    • 7、单链表头删
    • 8、单链表查找
    • 9、单链表插入
      • ☃️该位置之后插入
      • ☃️该位置之前插入(插入正常理解)
    • 10、单链表删除
    • 11、单链表销毁
  • 三、总代码
    • SeqListNode.h
    • SeqListNode.c
    • Test.c
  • 四、总结

一、前言

本篇讲述的是八种链表中面试和刷题中最容易出现的链表–无头单向不循环链表,过几天也会出一个性能最好的链表–有头双向循环链表,希望能够帮助你。

  • 下面的链表都是针对无头单向不循环这钟来说的。

链表是线性表的一种,它与顺序表不同的是它在内存中并不是连续存储,而是一个节点对应一个位置,前一个结点存着下一个结点的地址,从而产生了联系。如图:

在这里插入图片描述

二、链表实现

1、创建结构体类型

如图所示,链表和顺序表的不同之处:链表每个元素都是一个结点,是一个整体,既包含该位置的数值,又包含下一个位置的地址,但它不用像顺序表一样去记住有几个元素,因为它不是连续存放的,所以这样做根本没有任何意义。因此虽然顺序表和链表都用到了结构体,但他们是完全不同的意思。

代码:

typedef int SListDateType;

typedef struct SeqListNode
{
	SListDateType date;
	struct SeqListNode* next;
}SListNode;

2、创建结点

每次增加数据,我们都需要调用创建新结点这个函数,它的目的是在堆区开辟一个结点的内存空间,然后把我们新建数据的值赋上去,至于地址,我们在创建时并不知道赋什么,所以先置空,最后返回新建的结构体指针。

代码:

//创建新结点。
SListNode* BuyNewnode(SListDateType x)
{
	SListNode* newnode = malloc(sizeof(SListNode));
	assert(newnode);
	newnode->date = x;
	newnode->next = NULL;
	return newnode;
}

3、打印单链表

单链表的打印就是从第一个打印,直到最后一个,怎么判断是否结束,那就是最后一个结点指向的是NULL。

代码:

//打印单链表。
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("%d->",cur->date);
		cur = cur->next;
	}
	printf("NULL\n");
}

4、单链表尾插

单链表尾插挺简单的,就是先创建出来这个新节点,然后让原链表最后结点指向新节点就ok了。

//单链表尾插。
void SListPushBack(SListNode** pphead,SListDateType x)
{
	assert(pphead);

	SListNode* newnode = BuyNewnode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SListNode* cur = *pphead;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}

5、单链表头插

单链表头插,意味着要改变传过来的结构体指针(头指针),我们知道,形参只是实参的临时拷贝,那么如何实现改变实参呢?那就需要指针,但是实参本来就是一级指针,所以我们需要传二级指针,也就是实参(一级指针)的地址,这样才能实现修改。
知道了上面这些,那么剩下的就是让新节点地址赋给实参,然后让新结点指向原来的头结点就好。

代码:

//单链表头插。
void SListPushFront(SListNode** pphead, SListDateType x)
{
	assert(pphead);
	SListNode* newnode=BuyNewnode(x);
	newnode->next = *pphead;//先指向这个,如果先弄下面一步,就找不到原头节点的位置了。
	*pphead = newnode;//pphead是二级指针,解引用后就是一级指针,newnode也是一级指针,然后让newnode赋给pphead,这样就改变了实参。
}

6、单链表尾删

单链表尾删很简单,就是把最后的结点释放,倒数第二个结点便成了尾结点,此时它指向的是已经释放的结点,是野指针,我们要让它置空,他也应该置空,因为尾结点要指向空,不然之后用的时候程序不知道什么时候结束。
我们需要首先判断是否只有一个,因为只有一个的话,那就要改变实参了,释放这仅有的结点,让实参的值置空。

代码:

//单链表尾删。
void SListPopBack(SListNode** pphead)
{
	assert(pphead);

	assert(*pphead);//指针指向的内容不能是空的
	SListNode* cur = *pphead;
	SListNode* cur_ = NULL;//存倒数第二个结点的位置
	if (cur->next == NULL)
	{
		free(cur);
		*pphead = NULL;
		return;
	}
	while (cur->next)
	{
			cur_ = cur;//保留要释放结点的前一个位置,然后当下面用完cur(释放)后,让cur_(释放后的最后结点位置指向空)
			cur = cur->next;
	}
	free(cur);
	cur_->next = NULL;
}

7、单链表头删

单链表头删要让实参变为第二个结点的地址,也就是说要改变实参,所以还是要用二级指针。

代码:

//单链表头删。
void SListPopFront(SListNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SListNode* first = *pphead;
	*pphead = (*pphead)->next;
	free(first);
}

8、单链表查找

当我们想在某个值后面插入元素时,我们首先需要直到这个地方的地址,我们才能进行操作。所以便有了查找函数,实现原理就是逐个遍历,出现就返回这个结点地址,如果没出现,就返回空指针。

代码:

//单链表查找。
SListNode* SListFind(SListNode* phead, SListDateType x)
{
	assert(phead);//既然查找了,那么就不能为空链表,否则没有意义,这是使用者的问题。
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->date == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;//上面已经判断不能为空链表,所以这里返回的空指针指的就是找不到,而不是链表为空。
}

9、单链表插入

单链表插入如果时从该位置之后插入,很方便,不需要遍历找上一个结点的位置,直接用传过来的结点的位置进行操作。
但是一般意义上的插入都是在该位置之前,那么就需要遍历,找到上一个位置的结点,因为我们要用,这是单链表的弊端。

☃️该位置之后插入

代码:

//单链表插入(pos之后)。
void SListInsertAfter(SListNode* phead,SListNode* pos, SListDateType x)
{
	assert(pos);//插入默认是该链表不为空的,如果想要空的时候插入,用头插函数。
	SListNode* cur = phead;
	SListNode* newnode = BuyNewnode(x);
	while (cur!=pos)
	{
		cur = cur->next;
	}
	newnode->next = cur->next;
	cur->next = newnode;
}

☃️该位置之前插入(插入正常理解)

//单链表插入(pos之前)。
void SListInsertBefore(SListNode** pphead, SListNode* pos, SListDateType x)
{
	assert(pphead);

	assert(*pphead);//和刚才同理,链表没有元素的时候插入调用头插函数。
	SListNode* cur = *pphead;
	SListNode* newnode = BuyNewnode(x);
	if (cur->next == NULL)
	{
		*pphead = newnode;
		newnode->next = pos;
	}
	else
	{
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		cur->next = newnode;
		newnode->next = pos;
	}
}

10、单链表删除

单链表删除需要找到前一个结点,让前一个结点指想删除位置指向的位置,然后释放要删除的位置即可。

代码:

//单链表删除。
void SListEraseAfter(SListNode** pphead, SListNode* pos)
{
	assert(pphead);

	assert(*pphead);
	SListNode* cur = *pphead;
	if (cur == pos)
	{
		*pphead = pos->next;
		free(pos);
	}
	else
	{
		while (cur->next!=pos)
		{
			cur = cur->next;
		}
		cur->next = cur->next->next;//或者写成cur->next = pos->next;
		free(pos);
	}
}
  • 因为传的pos是一级指针,所以我们无法在函数里修改pos的值,我们只能修改pos指向位置的内容,当我们释放pos后,实参pos便指向释放后的位置,也就变成了野指针,所以我们需要在出函数后让pos置空。

11、单链表销毁

单链表销毁就是释放每个结点的空间,一直到最后结点,注意别释放前没做准备导致释放后找不到下一个结点的位置。

//单链表的销毁。
void SListDestroy(SListNode** pphead)
{
	assert(pphead);

	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* pc = cur;
		cur = cur->next;
		free(pc);
	}
}

三、总代码

SeqListNode.h

SeqListNode.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>


typedef int SListDateType;

typedef struct SeqListNode
{
	SListDateType date;
	struct SeqListNode* next;
}SListNode;

//创建新结点。
SListNode* BuyNewnode(SListDateType x);

//打印单链表。
void SListPrint(SListNode* phead);

//单链表尾插。
void SListPushBack(SListNode** pphead,SListDateType x);

//单链表头插。
void SListPushFront(SListNode** pphead, SListDateType x);

//单链表尾删。
void SListPopBack(SListNode** pphead);

//单链表头删。
void SListPopFront(SListNode** pphead);

//单链表查找。
SListNode* SListFind(SListNode* phead, SListDateType x);

//单链表插入。
//pos之后插入。
//不用从头开始查找,比较高效
void SListInsertAfter(SListNode* phead,SListNode* pos, SListDateType x);
//pos之前插入。
//还要从头开始查找,不合适
void SListInsertBefore(SListNode** pphead, SListNode* pos, SListDateType x);

//单链表删除。
void SListEraseAfter(SListNode** pphead, SListNode* pos);

//单链表的销毁。
void SListDestroy(SListNode** phead);

SeqListNode.c

SeqListNode.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqListNode.h"

//创建新结点。
SListNode* BuyNewnode(SListDateType x)
{
	SListNode* newnode = malloc(sizeof(SListNode));
	assert(newnode);
	newnode->date = x;
	newnode->next = NULL;
	return newnode;
}

//打印单链表。
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("%d->",cur->date);
		cur = cur->next;
	}
	printf("NULL\n");
}

//单链表尾插。
void SListPushBack(SListNode** pphead,SListDateType x)
{
	assert(pphead);

	SListNode* newnode = BuyNewnode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SListNode* cur = *pphead;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}

//单链表头插。
void SListPushFront(SListNode** pphead, SListDateType x)
{
	assert(pphead);

	SListNode* newnode=BuyNewnode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//单链表尾删。
void SListPopBack(SListNode** pphead)
{
	assert(pphead);

	assert(*pphead);//指针指向的内容不能是空的
	SListNode* cur = *pphead;
	SListNode* cur_ = NULL;//存倒数第二个结点的位置
	if (cur->next == NULL)
	{
		free(cur);
		*pphead = NULL;
		return;
	}
	while (cur->next)
	{
			cur_ = cur;//保留要释放结点的前一个位置,然后当下面用完cur(释放)后,让cur_(释放后的最后结点位置指向空)
			cur = cur->next;
	}
	free(cur);
	cur_->next = NULL;
}

//单链表头删。
void SListPopFront(SListNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SListNode* first = *pphead;
	*pphead = (*pphead)->next;
	free(first);
}

//单链表查找。
SListNode* SListFind(SListNode* phead, SListDateType x)
{
	assert(phead);
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->date == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//单链表插入(pos之后)。
void SListInsertAfter(SListNode* phead,SListNode* pos, SListDateType x)
{
	assert(pos);
	SListNode* cur = phead;
	SListNode* newnode = BuyNewnode(x);
	while (cur!=pos)
	{
		cur = cur->next;
	}
	newnode->next = cur->next;
	cur->next = newnode;
}

//单链表插入(pos之前)。
void SListInsertBefore(SListNode** pphead, SListNode* pos, SListDateType x)
{
	assert(pphead);

	assert(*pphead);
	SListNode* cur = *pphead;
	SListNode* newnode = BuyNewnode(x);
	if (cur->next == NULL)
	{
		*pphead = newnode;
		newnode->next = pos;
	}
	else
	{
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		cur->next = newnode;
		newnode->next = pos;
	}
}

//单链表删除。
void SListEraseAfter(SListNode** pphead, SListNode* pos)
{
	assert(pphead);

	assert(*pphead);
	SListNode* cur = *pphead;
	if (cur == pos)
	{
		*pphead = pos->next;
		free(pos);
	}
	else
	{
		while (cur->next!=pos)
		{
			cur = cur->next;
		}
		cur->next = cur->next->next;
		free(pos);
	}
}

//单链表的销毁。
void SListDestroy(SListNode** pphead)
{
	assert(pphead);

	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* pc = cur;
		cur = cur->next;
		free(pc);
	}
}

Test.c

Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqListNode.h"

void test1()
{
	SListNode* pc = NULL;
	SListPrint(pc);

	SListPushBack(&pc,0);
	SListPrint(pc);

	SListPushBack(&pc, 1);
	SListPrint(pc);

	SListPushBack(&pc, 2);
	SListPrint(pc);

	SListPushBack(&pc, 3);
	SListPrint(pc);

	SListPushBack(&pc, 4);
	SListPrint(pc);

	SListPushBack(&pc, 5);
	SListPrint(pc);

	SListPushBack(&pc, 6);
	SListPrint(pc);

	SListPushBack(&pc, 7);
	SListPrint(pc);
}

void test2()
{
	SListNode* pc = NULL;
	SListPrint(pc);

	SListPushFront(&pc, 0);
	SListPrint(pc);

	SListPushFront(&pc, 1);
	SListPrint(pc);

	SListPushFront(&pc, 2);
	SListPrint(pc);

	SListPushFront(&pc, 3);
	SListPrint(pc);

	SListPushFront(&pc, 4);
	SListPrint(pc);

	SListPushFront(&pc, 5);
	SListPrint(pc);

	SListPushFront(&pc, 6);
	SListPrint(pc);

	SListPushFront(&pc, 7);
	SListPrint(pc);
}
void test3()
{
	SListNode* pc = NULL;
	SListPrint(pc);

	SListPushBack(&pc, 0);
	SListPrint(pc);

	SListPushBack(&pc, 1);
	SListPrint(pc);

	SListPushBack(&pc, 2);
	SListPrint(pc);

	SListPushBack(&pc, 3);
	SListPrint(pc);

	SListPopBack(&pc);
	SListPrint(pc);

	SListPopBack(&pc);
	SListPrint(pc);

	SListPopBack(&pc);
	SListPrint(pc);

	SListPopBack(&pc);
	SListPrint(pc);
}
void test4()
{
	SListNode* pc = NULL;
	SListPrint(pc);

	SListPushBack(&pc,0);
	SListPrint(pc);

	SListPushBack(&pc, 1);
	SListPrint(pc);

	SListPushBack(&pc, 2);
	SListPrint(pc);

	SListPushBack(&pc, 3);
	SListPrint(pc);

	SListPushBack(&pc, 4);
	SListPrint(pc);

	SListPushBack(&pc, 5);
	SListPrint(pc);

	SListPushBack(&pc, 6);
	SListPrint(pc);

	SListPopFront(&pc);
	SListPrint(pc);

	SListPopFront(&pc);
	SListPrint(pc);

	SListPopFront(&pc);
	SListPrint(pc);

	SListPopFront(&pc);
	SListPrint(pc);

	SListPopFront(&pc);
	SListPrint(pc);

	SListPopFront(&pc);
	SListPrint(pc);
}
void test5()
{
	SListNode* pc = NULL;
	SListPushBack(&pc,0);
	//SListPushBack(&pc,1);
	//SListPushBack(&pc,2);
	SListPrint(pc);
	SListNode* pos = SListFind(pc,0);
	assert(pos);
	//SListInsertAfter(*pc, pos, 9);//pos之后插入。
	SListInsertBefore(&pc, pos, 5);//pos之前插入。
	SListPrint(pc);
	pos = SListFind(pc, 5);
	SListEraseAfter(&pc, pos);//删除后要置空
	pos = NULL;//这块被释放了,所以置空
	SListPrint(pc);
	SListDestroy(&pc);
}

int main()
{
	//test1();//测试尾插。
	//test2();//测试头插。
	test3();//测试尾删。
	//test4();//测试头删。
	//test5();//测试查找,插入,销毁。
	return 0;
}

四、总结

在这里插入图片描述

✨请点击下面进入主页关注大魔王
如果感觉对你有用的话,就点我进入主页关注我吧!

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

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

相关文章

gateway整合knife4j(微服务在线文档)

文章目录 knife4j 微服务整合一、微服务与单体项目文档整合的区别二、开始整合1. 搭建一个父子maven模块的微服务,并引入gateway2.开始整合文档 总结 knife4j 微服务整合 由于单个服务的knife4j 整合之前已经写过了,那么由于效果比较好,然后微服务的项目中也想引入,所以开始微…

【Linux】多线程的互斥与同步

目录 一、线程冲突 二、重入与线程安全 1、线程不安全的情况 2、线程安全的情况 3、不可重入的情况 4、可重入的情况 5、可重入和线程安全的联系 6、STL是否线程安全 7、智能指针是否线程安全 三、互斥锁 1、互斥锁的使用 2、基于RAII风格的互斥锁的封装 2.1Mutex…

ChatGPT-4回答电子电路相关问题,感觉它有思想,有灵魂,一起看看聊天记录

前几天发了一篇文章&#xff0c;讲了我们平常摸电脑或者其它电器设备的时候&#xff0c;会有酥酥麻麻的感觉&#xff0c;这个并不是静电&#xff0c;而是Y电容通过金属壳泄放高频扰动&#xff0c;我们手摸金属壳的时候&#xff0c;就给Y电容提供了一个泄放回路&#xff0c;所以…

全网抓包天花板教程,CSDN讲的最详细的Fiddler抓包教程。2小时包你学会

目录 前言 一、安装 Fiddler 二、打开 Fiddler 并设置代理 三、抓取 HTTP/HTTPS 流量 四、流量分析和调试 五、应用场景 六、注意事项 七、实际案例 八、拓展阅读 九、结论 前言 Fiddler 是一款功能强大的网络调试工具&#xff0c;可以用于捕获和分析 HTTP 和 HTTPS …

生物信息学有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是几个生物信息学领域的SCI期刊推荐&#xff1a; Bioinformatics&#xff1a; 该期刊是生物信息学领域最具影响力的SCI期刊之一&#xff0c;涵盖了生物信息学、计算生物学、系统生物学、生物医学工程等多个研究方向。 BMC Bioinformatics&#xff1a; 该期刊是生物信息学…

数据结构入门(C语言版)二叉树链式结构的实现

二叉树链式结构的实现 二叉树的概念及结构创建1、概念2、结构创建2、创建结点函数3、建树函数 二叉树的遍历1、前序遍历2、中序遍历3、后序遍历4、层序遍历 二叉树的销毁结语 二叉树的概念及结构创建 1、概念 简单回顾一下二叉树的概念&#xff1a; ★ 空树 ★非空&#xff1…

intellij 从2020升级到2023 踩坑实录

1.下载新版本intellij 工作机器上的intellij版本为2020社区版&#xff0c;版本比较老旧&#xff0c;需要进行升级。IDE这种提高生产力的工具&#xff0c;还是蛮重要的&#xff0c;也是值得稍微多花点时间研究一下的。升级之前就预计到了不会是那么简单&#xff0c;后面事实也证…

大型体检管理系统源码,Vs2012,C/S架构

体检管理系统源码&#xff0c;PEIS源码 一套专业的体检管理系统源码&#xff0c;核心功能有体检档案的录入、体检报告的输出、体检档案的统计查询和对比分析。该系统的使用&#xff0c;可以大大提高体检档案管理人员的工作效率&#xff0c;使体检档案的管理更加准确、全面、完…

以人为本的重点是有效网络安全计划的关键

安全和风险管理 (SRM) 领导者在根据九大行业趋势创建和实施网络安全计划时&#xff0c;必须重新考虑他们在技术和以人为本的元素之间的投资平衡。 以人为本的网络安全方法对于减少安全故障至关重要。 在控制设计和实施以及通过业务沟通和网络安全人才管理中关注人&#xff…

Python中的异常——概述和基本语法

Python中的异常——概述和基本语法 摘要&#xff1a;Python中的异常是指在程序运行时发生的错误情况&#xff0c;包括但不限于除数为0、访问未定义变量、数据类型错误等。异常处理机制是Python提供的一种解决这些错误的方法&#xff0c;我们可以使用try/except语句来捕获异常并…

基于linux:MySql-5.7二进制安装部署

基于linux&#xff1a;MySql-5.7二进制安装 1&#xff09;检查当前系统是否安装过Mysql [ ~]$ rpm -qa|grep mariadb mariadb-libs-5.5.56-2.el7.x86_64 //如果存在通过如下命令卸载 [ ~]$ sudo rpm -e --nodeps mariadb-libs //用此命令卸载mariadb2&#xff09;解压MySQ…

限流算法浅析

前言 在前文接口请求安全措施中&#xff0c;简单提到过接口限流&#xff0c;那里是通过Guava工具类的RateLimiter实现的&#xff0c;它实际上是令牌桶限流的具体实现&#xff0c;那么下面分别介绍几种限流算法&#xff0c;做一个更详细的了解。 固定窗口限流 1、核心思想 在…

基于 Flink CDC 的现代数据栈实践

摘要&#xff1a;本文整理自阿里云技术专家&#xff0c;Apache Flink PMC Member & Committer, Flink CDC Maintainer 徐榜江和阿里云高级研发工程师&#xff0c;Apache Flink Contributor & Flink CDC Maintainer 阮航&#xff0c;在 Flink Forward Asia 2022 数据集成…

初识C语言————4

文章目录 常见关键字 1、 关键字 typedef 2、关键字static define 定义常量和宏 指针 结构体 前言 这是博主初识C语言系列的最后一篇&#xff0c;之后博主会更新更详细的关于C语言学习的知识。希望各位老铁多多支持。 一、常见关键字 1、 关键字 typedef typedef 顾名思义是…

海康威视发布2022年ESG报告:科技为善, 助力可持续的美好未来

近日&#xff0c;海康威视正式发布《2022环境、社会及管治报告》&#xff08;以下简称“海康威视ESG报告”)&#xff0c;连续5年呈现在环境、社会发展、企业治理等领域的思考和创新成果。此外&#xff0c;报告中首次披露了碳中和业务蓝图&#xff0c;积极布局绿色生产、绿色运营…

HTTP特性

1 HTTP/1.1 的优点有哪些&#xff1f; 2 HTTP/1.1 的缺点有哪些&#xff1f; 3 HTTP/1.1 的性能如何&#xff1f; HTTP 协议是基于 TCP/IP&#xff0c;并且使用了「请求 - 应答」的通信模式&#xff0c;所以性能的关键就在这两点里。 3.1 长连接 早期 HTTP/1.0 性能上的一…

分布式Id生成之雪花算法(SnowFlake)

目录 前言 回顾二进制 二进制概念 运算法则 位&#xff08;Bit&#xff09; 字节&#xff08;Byte&#xff09; 字符 字符集 二进制原码、反码、补码 有符号数和无符号数 疑问&#xff1a;为什么不是-127 &#xff5e; 127 &#xff1f; 为什么需要分布式全局唯一ID…

sql中 join 的简单用法总结(带例子)

join 常见的用法有&#xff1a; 目录 left join&#xff08;left outer join&#xff09;right join&#xff08;right outer join&#xff09;join&#xff08;inner join&#xff09;full join&#xff08;full outer join 、outer join&#xff09;cross join 说明&#xf…

docker自定义镜像

文章目录 一、自定义镜像1.1 镜像结构1.2 Dockerfile1.3 dockerCompose1.3.1 dockerCompose的作用1.3.2 dockerCompose的常用命令 1.4 镜像仓库 一、自定义镜像 1.1 镜像结构 自定义镜像通常包含三个基本部分&#xff1a;基础镜像、应用程序代码和配置文件。 基础镜像&#…

asp.net+sqlserver+C#网上洗衣店的设计与实现

选题的目的、理论与实践意义&#xff1a; 随着洗衣店服务的日渐完善和复杂&#xff0c;以前单纯的文本记录人工管理方式不仅效率低下&#xff0c;且易出错&#xff0c;直接导致管理费用的增加&#xff0c;服务质量的下降。由于这种人工管理方式不能完全适应需求的发展&#xff…