【数据结构初阶】单链表(附全部码源)

单链表

    • 1,单链表的概念及结构
    • 2,单链表的实现
      • 2.1初始化内容(所需文件,接口)
      • 2.2申请结点
      • 2.3打印单链表
      • 2.4尾插
      • 2.5头插
      • 2.6尾删
      • 2.7头删
      • 2.8查找
      • 2.9在pos位置之后插入
      • 2.10在pos位置前面插入
      • 2.11删除pos之后的值
      • 2.12删除pos位置的值
      • 2.13销毁链表
    • 3.全部码源

1,单链表的概念及结构

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
在这里插入图片描述
在这里插入图片描述
现实中 数据结构中
在这里插入图片描述

2,单链表的实现

2.1初始化内容(所需文件,接口)

所需文件

头文件->SList.h
源文件->test.c
源文件->SList.c

接口(SList.h中)

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


typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);

SLTNode* BuySListNode(SLTDataType x);
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);

void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);


SLTNode* SLTFind(SLTNode* phead, SLTDataType x);

// 在pos之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);

// 在pos以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);

// 删除pos的后一个位置
void SLTInsertAfter(SLTNode* pos);

2.2申请结点

SLTNode* BuySListNode(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode*));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	else
	{
		newnode->date = x;
		newnode->next = NULL;
	}
	return newnode;
}

2.3打印单链表

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->date);
		cur = cur->next;
	}
	printf("NULL\n");
}

2.4尾插

void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
    assert(pphead);//pphead不能为空,pphead为空说明里面没有存指向头节点指针的地址,那就说明没有链表
	SLTNode* newnode = BuySListNode(x);//由于在头插和随机插入的过程中也会涉及到节点的创建,所以这里把节点的创建单独封装了一个函数

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)//假如链表为空这里就非法访问了,因此要先判断
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

2.5头插

头插显然是要改变头指针存放的地址,因此形参也需要传递二级指针。头插无需单独考虑空链表的情况

void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
	SLTNode* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

2.6尾删

尾删先要遍历一遍链表找到最后一个节点将其释放掉,还要找到倒数第二个节点将它的指针域中存的地址改为NULL。所以定义两个指针让他们同时去遍历链表,一个找尾,另一个找倒数第二个节点。需要注意的是空链表和只有一个节点的链表的情况,空链表无法进行尾删,而只有一个节点的链表在尾删后会变成一个空链表,这意味着要改变头指针里面存放的地址,所以尾删形参也要传递二级指针。

void SLTPopBack(SLTNode** pphead)
{
    assert(pphead);
	assert(*pphead);//暴力检查是否为空链表,空链表不能删数据
	/*if (*pphead == NULL)//温柔的进行检查
	{
		return;
	}*/
	//只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//有多个节点
	else
	{
		/*SLTNode* tailPrev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tailPrev = tail;
			tail = tail->next;
		}
		free(tail);
		tailPrev = NULL;*/
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

2.7头删

头删很明显需要改变头指针中存放的地址,所以形参仍然需要传递二级指针。头删只需要注意链表是否为空,空链表无法进行删除。此外在进行头删的时候记得将原来的头节点释放掉,因此在改变头节点之前需要先保留原来头结点的地址,否则在更换完新的头节点后就找不到原来的头节点了。

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);

	assert(*pphead);

	SLTNode* newnode = (*pphead)->next;//假如链表为空,这里就会发生越界,因此要判断链表是否为空
	free(*pphead);
	*pphead = newnode;
}

2.8查找

其实就是遍历一遍链表,但是只能返回第一次出现的地址。查找可以当修改来使用,我们查找到节点的地址后就可以通过地址去修改数据域中存储的数据。

SLTNode* SLTFind(SLTNode* phead, SLTDateType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->date == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

2.9在pos位置之后插入

先让newnode的指针域存储pos后一个节点的地址,再让pos的指针域存newnode的地址

void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{
	assert(pos);
	SLTNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

2.10在pos位置前面插入

和尾插类似,但此时只需要遍历链表找到pos位置的前一个节点即可,同样需要注意pos是头结点的情况,此时就成头插了,需要改变头指针中存的地址,因此函数的形参需要传二级指针。

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	assert(pphead);
	assert(pos);
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		if (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

2.11删除pos之后的值

注意不能写成后面这样:pos->next = pos->next->next。这样写虽然把pos位置后面的节点从链表中剔除出去了,但并没有真正意义上的实现删除,因为每一个节点都是通过malloc在堆上申请的,不使用的时候要主动的去释放掉,也就是free掉,把这块空间归还给操作系统,否则会导致内存泄漏。而上面那样写,就会导致pos后面的节点丢失,无法进行释放,正确的做法是在执行这条语句之前把pos后边节点的地址先保存起来。

void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	//检查pos是不是尾结点
	assert(pos->next);

	SLTNode* posNext = pos->next;

	pos->next = posNext->next;
	free(posNext);
	posNext = NULL;
}

2.12删除pos位置的值

pos可能是头结点的地址,因此形参要用二级指针。

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

2.13销毁链表

void SListDestroy(SLTNode* plist)
{
	assert(plist);
	SLTNode* cur = plist;
	while (cur)
	{
		SLTNode* pur = cur;
		cur = cur->next;
		free(pur);
	}
}

3.全部码源

SList.c

#include"SList.h"

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	//while (cur != NULL)
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}

	printf("NULL\n");
}

SLTNode* BuySListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);

	if (*pphead == NULL)
	{
		// 改变的结构体的指针,所以要用二级指针
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		// 改变的结构体,用结构体的指针即可
		tail->next = newnode;
	}	
}

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}

void SLTPopBack(SLTNode** pphead)
{
	// 1、空
	assert(*pphead);

	// 2、一个节点
	// 3、一个以上节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//SLTNode* tailPrev = NULL;
		//SLTNode* tail = *pphead;
		//while (tail->next)
		//{
		//	tailPrev = tail;
		//	tail = tail->next;
		//}

		//free(tail);
		tail = NULL;
		//tailPrev->next = NULL;

		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}
}

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);

	// 空
	assert(*pphead);

	// 非空
	SLTNode* newhead = (*pphead)->next;
	free(*pphead);
	*pphead = newhead;
}

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

// 在pos以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuySListNode(x);
	pos->next = newnode;
	newnode->next = pos->next;
}

// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		prev->next = pos->next;
		free(pos);
		//pos = NULL;
	}
}

// 删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);

	// 检查pos是否是尾节点
	assert(pos->next);

	SLTNode* posNext = pos->next;

	pos->next = posNext->next;

	free(posNext);
	posNext = NULL;
}

SList.h

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


typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);

SLTNode* BuySListNode(SLTDataType x);
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);

void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);


SLTNode* SLTFind(SLTNode* phead, SLTDataType x);

// 在pos之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);

// 在pos以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);

// 删除pos的后一个位置
void SLTInsertAfter(SLTNode* pos);

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"

void TestSList1()
{
	int n;
	printf("请输入链表的长度:");
	scanf("%d", &n);
	printf("\n请依次输入每个节点的值:");
	SLTNode* plist = NULL;

	for (size_t i = 0; i < n; i++)
	{
		int val;
		scanf("%d", &val);
		SLTNode* newnode = BuySListNode(val);

		// 头插
		newnode->next = plist;
		plist = newnode;
	}

	SLTPrint(plist);

	SLTPushBack(&plist, 10000);
	SLTPrint(plist);
}

void TestSList2()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);
}

void TestSList3()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);


	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	// SLTPopBack(&plist);
	// SLTPrint(plist);
}

void TestSList4()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	//SLTPopFront(&plist);
	SLTPrint(plist);
}

void TestSList5()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	SLTNode* pos = SLTFind(plist, 3);
	SLTInsert(&plist, pos, 30);
}


void TestSList6()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	int x;
	scanf("%d", &x);
	SLTNode* pos = SLTFind(plist, x);
	if (pos)
	{
		SLTInsertAfter(pos, x * 10);
	}
	SLTPrint(plist);
}

void TestSList7()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	int x;
	scanf("%d", &x);
	SLTNode* pos = SLTFind(plist, x);
	if (pos)
	{
		//SLTErase(&plist, pos);
		SLTEraseAfter(pos);
		pos = NULL;
	}
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

}
int main()
{
	TestSList4();

	return

💘不知不觉,【数据结构初阶】单链表以告一段落。通读全文的你肯定收获满满,让我们继续为数据结构学习共同奋进!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Synopsys Bug记录】DC综合报错(显示warning:Unable to resolve reference)

文章目录 一、问题描述二、问题所在三、问题解决总结4.1 Warning的产生4.2 代码风格4.3 网表正确性 一、问题描述 在综合一个SOC时&#xff0c;发现综合后的门级网表文件缺少了apb系统下的子模块的网表。该SOC已经成功在FPGA上运行了&#xff0c;按理说在设计上是没有问题的。在…

TableUtilCache:针对CSV表格进行的缓存

TableUtilCache:针对CSV表格进行的缓存 文件结构 首先来看下CSV文件的结构&#xff0c;如下图&#xff1a; 第一行是字段类型&#xff0c;第二行是字段名字&#xff1b;再往下是数据。每个元素之间都是使用逗号分隔。 看一下缓存里面存储所有表数据的字段 如下图&#xff…

AH4056线性锂电池充电IC:高效、安全的充电解决方案

随着移动设备的普及&#xff0c;人们对电池续航能力的要求越来越高。为了满足这一需求&#xff0c;电池充电技术不断创新。本文将为您介绍一款AH4056线性锂电池充电IC&#xff0c;采用同步整流技术&#xff0c;具有宽输入电压范围、大充电电流、温度保护等优点&#xff0c;适用…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 4》(8)

《Linux操作系统原理分析之Linux 进程管理 4》&#xff08;8&#xff09; 4 Linux 进程管理4.4 Linux 进程的创建和撤销4.4.1 Linux 进程的族亲关系4.4.2 Linux 进程的创建4.4.3 Linux 进程创建的过程4.4.4 Linux 进程的执行4.4.5 Linux 进程的终止和撤销 4 Linux 进程管理 4.…

nginx学习(1)

一、下载安装NGINX&#xff1a; 先安装gcc-c编译器 yum install gcc-c yum install -y openssl openssl-devel&#xff08;1&#xff09;下载pcre-8.3.7.tar.gz 直接访问&#xff1a;http://downloads.sourceforge.net/project/pcre/pcre/8.37/pcre-8.37.tar.gz&#xff0c;就…

python爬取穷游网景点评论

爬取穷游网的景点评论数据&#xff0c;使用selenium爬取edge浏览器的网页文本数据。 同程的评论数据还是比较好爬取&#xff0c;不像大众点评需要你登录验证杂七杂八的&#xff0c;只需要找准你想要爬取的网页链接就能拿到想要的文本数据。 这里就不得不提一下爬取过程中遇到的…

FFmpeg 6.1 发布,7.0时代即将来临

11月10日&#xff0c;FFmpeg 6.1正式发布。 FFmpeg 发布版本的时候&#xff0c;按照惯例&#xff0c;会选择一些物理学家名字作为代号&#xff0c;这一新版本代号为“Heaviside”。主要为纪念伟大的英国数学家和物理学家奥利弗黑维塞&#xff08;Oliver Heaviside)。 奥利弗黑维…

100套Axure RP大数据可视化大屏模板及通用组件库

106套Axure RP大数据可视化大屏模板包括了多种实用美观的可视化组件库及行业模板库&#xff0c;行业模板涵盖&#xff1a;金融、教育、医疗、政府、交通、制造等多个行业提供设计参考。 随着大数据的发展&#xff0c;可视化大屏在各行各业得到越来越广泛的应用。可视化大屏不再…

Simulink 自动代码生成电机控制:模型预测控制(MPC)模块使用总结(1)

目录 前言 MPC模块使用步骤和参数设计 电机控制系统验证 MPC参数调整 MPC和PI控制器比较 总结 前言 前面尝试了基于电机DQ轴电流环的传递函数设计PI控制器的参数&#xff0c;最近尝试了下模型预测控制&#xff08;MPC&#xff09;对电流环进行控制&#xff0c;这里总结一下…

MySQL 运算符二

逻辑运算符 逻辑运算符用来判断表达式的真假。如果表达式是真&#xff0c;结果返回 1。如果表达式是假&#xff0c;结果返回 0。 运算符号作用NOT 或 !逻辑非AND逻辑与OR逻辑或XOR逻辑异或 1、与 mysql> select 2 and 0; --------- | 2 and 0 | --------- | 0 | -…

pipeline agent分布式构建

开启 agent rootjenkins:~/learning-jenkins-cicd/07-jenkins-agents# docker-compose -f docker-compose-inbound-agent.yml up -d Jenkins配置添加 pipeline { agent { label docker-jnlp-agent }parameters {booleanParam(name:pushImage, defaultValue: true, descript…

【日常】爬虫技巧进阶:textarea的value修改与提交问题(以智谱清言为例)

序言 记录一个近期困扰了一些时间的问题。 我很喜欢在爬虫中遇到问题&#xff0c;因为这意味着在这个看似简单的事情里还是有很多值得去探索的新东西。其实本身爬虫也是随着前后端技术的不断更新在进步的。 文章目录 序言Preliminary1 问题缘起1.1 Selenium长文本输入阻塞1.2…

60V100V降压ic推荐

在电源降压领域&#xff0c;一款优秀的降压IC需要具备高效、稳定、安全、易于使用等特性。今天&#xff0c;我们为大家推荐一款具有9.2V至100V输入电压范围、4.5A连续输出电流、96%峰值效率、495μA工作静态电流、峰值电流模式控制、100V19mQ高边和低边MOS、固定150kHz开关频率…

C/C++ 字符 - ‘0‘ 或者 + ‘0‘ 的含义及区别(从ASCII码深度解析,小白一看就懂!!!)

目录 一、前言 二、什么是ACSII码&#xff1f; 三、深度理解字符 - ‘0‘ 或者 ‘0‘ 四、实战演练 五、共勉 一、前言 想必大家在刷题或者是看别人写的代码中&#xff0c;经常会遇到 s[i]-’0‘ 或者 s[i]’0‘ 这个情况&#xff0c;初次遇到这种代码&#xff0c;肯定是…

4.1指令系统-指令格式

现代计算机的结构 计算机的工作过程 指令的定义 指令&#xff08;又称机器指令&#xff09;&#xff1a; 是指示计算机执行某种操作的命令&#xff0c;是计算机运行的最小功能单位。 一台计算机的所有指令的集合构成改机指令系统&#xff0c;也称为指令集。 注意&#xff1…

拼多多百亿补贴商品详情API接口系列

拼多多API接口是拼多多网提供的一种应用程序接口&#xff0c;允许开发者通过程序访问拼多多网站的数据和功能。通过拼多多API接口&#xff0c;开发者可以开发各种应用程序&#xff0c;如店铺管理工具、数据分析工具、购物比价工具等。在本章中&#xff0c;我们将介绍拼多多API接…

Jquery 通过class名称属性,匹配元素

UI自动化过程中&#xff0c;常常需要判断某个元素是否满足条件&#xff0c;再走不通的脚本逻辑&#xff1b;、本文介绍如何通过jquery判断菜单是否展开&#xff0c;来决定是否执行菜单展开脚本&#xff1b;Jquery通过class名称属性&#xff0c;匹配元素 我们先分析&#xff0c;…

HTML5学习系列之项目实战1

HTML5学习系列之项目实战1 前言代码记录问题总结 前言 学习记录 代码 <div id"player"><audio id"musicbox"></audio><div id"controls" class"clearfix controls"><div id"play" class"…

Android 当中的 Fragment 协作解耦方式

Android 当中的 Fragment 协作解耦方式 文章目录 Android 当中的 Fragment 协作解耦方式第一章 前言介绍第01节 遇到的问题第02节 绘图说明 第二章 核心代码第01节 代理人接口第02节 中间人 Activity第03节 开发者A第04节 开发者B第05节 测试类 第一章 前言介绍 第01节 遇到的…

Ubuntu22.04 Apache2安装SSL证书 https

一、免费证书申请 https://help.aliyun.com/zh/ssl-certificate/user-guide/overview-of-free-certificates 得到 三、配置 执行以下命令&#xff0c;打开default-ssl.conf文件。 vim /etc/apache2/sites-available/default-ssl.conf 在default-ssl.conf配置文件中&#xff…