数据结构- 顺序表-单链表-双链表 --【求个关注!】

文章目录

  • 一 顺序表
    • 代码:
  • 二 链表
    • 单链表
    • 双向链表


一 顺序表

顺序表是线性表的一种
所谓线性表指一串数据的组织存储在逻辑上是线性的,而在物理上不一定是线性的
顺序表的底层实现是数组,其由一群数据类型相同的元素组成,其在逻辑与物理上均是线性的。

代码:

对于顺序表的结构及各种操作函数的声明
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS 1
#include <assert.h>
#include<string.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

//顺序表的声明
typedef int Datatype;  //规定顺序表的基本元素是什么类型
struct SeqList {
	Datatype* arr;   //顺序表空间的首地址
	int size;        //顺序表中当前元素的个数
	int capacity;    //顺序表当前所申请的空间个数,单位为数据类型大小
};

//初始化一个顺序表的声明
void Initialize(struct SeqList* ps);
// 插入数据操作
//尾插法
void TailInsert(struct SeqList* ps, Datatype x);
//头插法
void HeadInsert(struct SeqList* ps, Datatype x);
//在指定位置插入数据
void RanInsert(struct SeqList* ps, int pos, Datatype x);
//删除数据操作
//头删法
void HeadDelete(struct SeqList* ps);
//尾删法
void TailDelete(struct SeqList* ps);
//在指定位置删除数据
void RanInsert(struct SeqList* ps, int pos);
//查找数据,返回下标
int Select(struct SeqList* ps, Datatype x);


//删除顺序表的声明
void DeleteList(struct SeqList* ps);

对于顺序表及各种操作函数的实现:
在这里插入图片描述

#include "seqlist.h"
// 初始化一个顺序表
void Initialize(struct SeqList * ps) {
	//初始化地址
	ps->arr = NULL;  //NULL在文件string.h中定义
	ps->size = ps->capacity = 0;
}
// 判断空间是否够用,不够的话申请空间
void DeterSpace(struct SeqList* ps) {
	if (ps == NULL) {
		perror("ps");
	}
	if (ps->size == ps->capacity) {
		// 如果并未分配空间,返回
		int  exsp = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		ps->capacity = exsp; //将扩展后的空间大小记录下来
		Datatype* p1 = NULL;
		// 扩展空间大小
		p1 = realloc(ps->arr, exsp * sizeof(Datatype));
		assert(p1);
		ps->arr = p1;
	}
	


}
//尾插法
void TailInsert(struct SeqList* ps, Datatype x) {
	if (ps == NULL) {
		perror("ps");
	}
	//需要先确定空间是否够用?
	//如果顺序表中的元素个数等于空间大小,则需要扩展空间--申请原来空间两倍的空间
	DeterSpace(ps);
	// 将值插到顺序表末尾
	ps->arr[ps->size++] = x;

}
// 头插法:
void HeadInsert(struct SeqList* ps, Datatype x) {
	//对于头插法,我们也需要判断空间是否足够用
	DeterSpace(ps);
	//在保证了空间之后,将顺序表中数据先往右移动一个元素大小,再进行插入
	for (int i = ps->size; i > 0; i--) {
		ps->arr[i] = ps->arr[i - 1];

	}
	//空出首地址之后:
	ps->arr[0] = x;
	//元素的个数也需要++
	ps->size++;
}
// 在指定位置插入一个数据
void RanInsert(struct SeqList *ps,int pos,Datatype x) {
	assert(ps);
	assert(pos>=0 &&pos<=ps->size -1);
	//在指定位置插入一个数据可以由 将此位置及此位置以后的数据往后移动一位,然后再将数据插入此位置
	//在此之前要判断空间是否够用
	DeterSpace(ps);
	for (int i = ps->size-1; i >= pos; i--) {
		ps->arr[i+1] = ps->arr[i]; //将pos在内之后的数据往右移动一位

	}
	ps->arr[pos] = x;
	ps->size++;
}
// 头删法  
// 即删除顺序表中的首个元素
void HeadDelete(struct SeqList* ps) {
	for (int i = ps->size - 1; i > 0; i++) {
		ps->arr[i - 1] = ps->arr[i];
   }
	ps->arr[ps->size - 1] = 0;
	ps->size--;
}
// 尾删法  -- 找到最后一个数组元素置为0;
void TailDelete(struct SeqList* ps) {
	//直接通过ps->size找到顺序表中最后一个元素置为0
	ps->arr[ps->size - 1] = 0;
	ps->size--;

}
// 删除指定位置的数据 
void RanInsert(struct SeqList*ps,int pos) {
	//我们删除指定位置的数据后,可以由在此位置之后的数据整体往前移动来实现
	assert(ps);
	assert(0 <= pos && pos <= ps->size - 1);
	//在下标pos之前的数据向前移动
	for (int i = ps->size - 1; i > pos; i--) {
		ps->arr[i - 1] = ps->arr[i]; 
	}
	ps->arr[ps->size - 1] = 0;//将顺序表原来的最后一个元素位置置为0;
	ps->size--; // 元素个数-1

}
// 查找
// 返回相应的下标
int Select(struct SeqList * ps,Datatype x) {
	assert(ps);
	for (int i = 0; i < ps->size - 1; i++) {
		if (ps->arr[i] == x) {
			return i;
		}

	}

	//找不到返回0
	return 0;

}
// 删除一个顺序表
void DeleteList(struct SeqList* ps) {
	if (ps == NULL) {
		exit(1);
	}
	free(ps->arr);
	ps->arr = NULL;
	//并将元素个数,空间记录清除
	ps->size = ps->capacity = 0;

}

二 链表

链表是线性表的一种
1   链表的逻辑结构是线性的,但其物理存储结构不是线性的。
2   链表的基本元素为结点,结点由数据域与指针域组成,数据域中存放存储的数据,
指针域中存放指向其他结点的指针, 结点之间通过指针互相联系。
链表共有8种(2*2*2)
链表的三种特性分别为:      带头与不带头
                                    ( 所谓头即指不携带有效数据的头节点)
                                              单向与双向链表
                                              循环与不循环
                                     (所谓循环即第一个结点与尾结点链接在一起)

链表:

在这里插入图片描述

在这里插入图片描述
最常见的有两种:单链表与双向链表

单链表

单链表的全称是不带头单向不循环链表

我在代码中的注释所写的首节点是可以携带有效数据的,为了避免与头节点混淆,所以我用首节点作为名称,而不是头节点!
在这里插入图片描述

代码:

#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
// 声明单链表结点
// 对链表中数据类型的声明
typedef int Datatype;
typedef struct ListNode {
	Datatype data;      //结点中的数据
	struct ListNode* Next;//指向下一个结点的指针
}Node;
//打印链表函数声明
void PrintList(Node* ps);
//创建新结点并赋值的函数声明
Node* CreateNode(Datatype x);
// 插入数据
// 头插
void HeadInsert(Node** phead, Datatype x);
//尾插
void TailInsert(Node** phead, Datatype x);
// 尾删
void TailDelete(Node** phead);
// 头删
void HeadDelete(Node** phead);
// 查找
Node* Select(Node* phead, Datatype x);
// 在指定位置之前插入数据
void RanLeftInsert(Node** phead, Node* pos, Datatype x);
// 在指定位置之后插入数据
// 我们不需要首节点的参数,因为不需要遍历,也不需要在首节点之前插入数据
void RanRightInsert(Node* pos, Datatype x);
// 删除pos位置的结点
void DeleteNode(Node** phead, Node* pos);
// 删除pos之后的结点
void DeleteAfterNode(Node* pos);
// 销毁链表:
void Distory(Node** phead);

在这里插入图片描述
代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//打印链表函数
void PrintList(Node* ps) {
	while (ps!=NULL) {
		printf("%d\n", ps->data);
		ps = ps->Next;
	}
}
// 创建新结点:
Node* CreateNode(Datatype x) {
	Node* newnode = (Node*)malloc(sizeof(Node));
	if (newnode == NULL) {
		perror("malloc");
		exit(1);   //退出程序
	}
	newnode->data = x;
	newnode->Next = NULL;
	return newnode;//返回新结点的指针
}
// 插入数据
// 头插
void HeadInsert(Node ** phead,Datatype x ) {
   
	Node* newnode = CreateNode(x);
	// 将新节点插入到原链表的首部
	newnode->Next = *phead;
	// 将新节点即新链表首节点的地址赋给*phead
	*phead = newnode;
}

//尾插
void TailInsert(Node** phead, Datatype x) {
    //参数为指向 指定链表的首结点 的指针与要插入的数据
	//如果链表一开始为空,即phead =NULL时,则ptail->Next则有问题,
	 Node* ptail = *phead;
	 if (* phead == NULL) {
		* phead = CreateNode(x); //在函数调用结束后,函数中的局部变量会被收回,
		                        //形参phead值的改变不会影响到实参,如果采用首节点二重指针
		                        // 则可以通过形参改变首节点的指针。
	 }
	 else {
		 //先找到尾结点
		 while (ptail->Next != NULL) {
			 ptail = ptail->Next;
		 }
		 //在找到尾结点后,在尾结点后插入新的结点,并赋值
		 ptail->Next = CreateNode(x);
	 }

}
// 尾删
void TailDelete(Node**phead) {
	//链表不能为空
	assert(phead && *phead);
	//我们在删除尾结点之后,尾结点之前的指针就变为野指针,我们需要找到此指针并置为空
	//当链表只有一个结点时:
	if ((*phead)->Next == NULL) {
		free(*phead);
		*phead = NULL;
	}
	else {
		// 创建存放指向尾结点的指针
		Node* prev = NULL;
		Node* ptail = *phead;
		//查找头节点
		while (ptail->Next) {// ptail->Next !=	NULL;
			prev = ptail;
			ptail = ptail->Next;
		}
		//在找到尾结点后:
		free(ptail);
		ptail = NULL;
		//将指向尾结点的指针置为空
		prev->Next = NULL;
	}
}
// 头删
void HeadDelete(Node **phead) {
	assert(phead && *phead); //链表不能为空
	//在删除首节点之后,我们需要能够找到下一个结点的地址
	Node* next = (*phead)->Next;//->的优先级比*大
	free(*phead);
	*phead = next;
}
// 查找
Node* Select(Node* phead, Datatype x) {
	Node* sel = phead;
	while (sel) {
		if (sel->data == x) {
			return sel;

		}
		sel = sel->Next;
	}
}
// 在指定位置之前插入数据
void RanLeftInsert(Node**phead,Node *pos,Datatype x) {
	//因为首节点可能会改变,所以用二级指针作为形参,避免用一级指针无法改变链表的首地址
    //在指定位置之前插入数据的情况只有图中的三种情况,在链表之前,在链表中,在链表最后一个元素之前
	assert(phead&& *phead);  
	assert(pos);          //因为pos不能为空,所以*phead也不能为空,否则*phead为空时,也可以进行头插
	if (pos == *phead) {
	  //pos在首节点处,这相当于头插法
		
		HeadInsert(phead, x);
	}
	else {
     //pos位置在链表中与链表最后一个元素上,操作没有本质区别
		Node* newnode = CreateNode(x);
		Node* prev = *phead;
		while (prev->Next!=pos) {
      		prev = prev->Next;
		}
		//当找到了pos之前的prev时:
		newnode->Next = pos;
		prev->Next = newnode;
	}
}
// 在指定位置之后插入数据
// 我们不需要首节点的参数,因为不需要遍历,也不需要在首节点之前插入数据
void RanRightInsert(Node * pos,Datatype x) {
	assert(pos);
	//我们先创建新结点
	Node* newnode = CreateNode(x);
	//将结点插入到pos之后:
	newnode->Next = pos->Next;
	pos->Next = newnode;
}
// 删除pos位置的结点
void DeleteNode(Node** phead, Node* pos) {
	assert(phead && *phead);
	assert(pos);
	//在删除pos结点时,我们需要将pos之后的结点与pos之前的结点链接起来,
	//pos之后的结点可以用pos->next找到,pos之前的结点需要在遍历时,用变量prev保存!
	if (pos == *phead) {
		//当pos是首节点时,此时的情况即头删法
		HeadDelete(phead);
		

	}
	else {

		Node* prev = *phead;
		//在采用这条判断语句的前提是:pos不是首结点
		while (prev->Next != pos) {
			prev = prev->Next;
		}
		//当找到prev时,将pos之后的结点与pos之前的结点链接起来;
		prev->Next = pos->Next;
		//释放掉pos
		free(pos);
	}
}
// 删除pos之后的结点
void DeleteAfterNode(Node* pos) {
	assert(pos && pos->Next);
	//要删除pos之后的结点,要将pos->next之后的结点与pos链接起来,再删除pos
	Node* del = pos->Next;     
	pos->Next = del->Next;
    free(del);//难道此时pos->Next的值不会发生变化?
	del = NULL;
	// 兄弟们,下面的c打印的值是多少?它的值会不会随着a的变化而变化呢?
	//int a = 1;
	//int c = a;
	// a++;
	//printf("%d\n",c);
   
}
// 销毁链表:
void Distory(Node **phead) {
	assert(phead && *phead);
	Node* pcur = *phead;
	while (pcur != NULL) {//链表的销毁需要一个结点一个结点的释放
		Node* next = pcur->Next;
		free(pcur);
		pcur = next;
	}
	*phead = NULL;
  
}

在这里插入图片描述

双向链表

双向链表的全称是带头双向循环链表

分析图:

在这里插入图片描述
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS 1
#include<string.h>
#include<assert.h>
#include<stdlib.h>
typedef int Datatype;
//定义双链表结点的格式
typedef struct ListNode {
	Datatype data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;
//函数操作的声明:
// 创建结点
void CreateNode(Datatype x);
// 打印链表:
void PrintList(ListNode* phead);
//初始化链表
void Initialize(ListNode** phead);
//插入数据操作
// 尾插法:
// 我们不需要改变头节点,所以用一级指针作为形参即可
void TailInsert(ListNode* phead, Datatype x);
//头插法
void HeadInsert(ListNode* phead, Datatype x);
// 尾删法
void TailDelete(ListNode* phead);
//头删:
void HeadDelete(ListNode* phead);
// 查找
ListNode* Select(ListNode* phead, Datatype x);
// 在指定位置之后插入数据
ListNode* AfterSelect(ListNode* pos, Datatype x);
//删除指定位置pos节点
//pos的形参是一级而不是二级是因为前面的函数形参皆是一级指针 ,这样保证了接口的一致性,确保了
//                                                    他人的方便调用与解读。
void DeleteNode(ListNode* pos, ListNode* phead);
//销毁链表:
void Distory(ListNode* phead);

在这里插入图片描述

#include"List.h"

// 打印链表:
void PrintList(ListNode *phead){
	//我们遍历双向链表的条件是什么?
	//我们能够找到判断条件是因为,我们知道双向链表从哪里开始到哪里结束是一个循环,我们只是把自己所知道的
	//用符号的形式表述出来,这是一种能力!
	ListNode* p1 = phead->next;
		while(p1 !=phead) 
		{
			printf("%d\n", p1->data);
			p1 = p1->next;
	    }
}
//初始化链表
//因为双向链表是带头的【即有头节点】,所以需要先为链表创建一个头节点
void Initialize(ListNode ** phead) {
	*phead = CreateNode(-1);//创建头节点并随便赋值为1
    
}
//创建新节点并赋值函数
ListNode * CreateNode(Datatype x) {
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->data = x;
//既然双向链表是循环的,我们在创建结点时,可以先使其自循环!
	newnode->next = newnode;
	newnode->prev = newnode;
	return newnode;	
}
//插入数据操作
// 尾插法:
// 我们不需要改变头节点,所以用一级指针作为形参即可
void TailInsert(ListNode * phead,Datatype x) {
	ListNode* newnode = CreateNode(x);//创建一个新结点
	//用phead->prev即可找到尾结点
	//找到后
	phead->prev->next = newnode;//将新节点插入到链表尾部
	newnode->next = phead;
	newnode->prev = phead->prev; 
	phead->prev = newnode;

}
//头插法
void HeadInsert(ListNode* phead, Datatype x) {
	ListNode* newnode = CreateNode(x);
	//指针先动谁?
	//先操作phead->next指向的结点
	//如果先操作phead结点,则在将phead->next指向新节点后,后面的链表部分就找不到位置了
	//头插法最多动4个指针:头节点的next,原来第二个结点(可能没有)的prev,新节点的prev与next指针

	newnode->next = phead->next;
	newnode->prev = phead;

	phead->next->prev = newnode;
	phead->next = newnode;
	
}
// 尾删法
void TailDelete(ListNode * phead) {
	// 尾删首先要找到尾结点,然后安排好相应的结点
	//这是判断链表有效,必须有头节点
	assert(phead);
	//这是判断链表不能为空,否则无法删除
	assert(phead->next!=phead);
	// phead del del->prev //涉及的节点
	ListNode* del = phead->prev;
	del->prev->next = phead;
	phead->prev = del->prev;

	// 删除del节点
	free(del);
	del = NULL;

}
//头删:
void HeadDelete(ListNode* phead) {
	assert(phead && phead->next != phead);
	ListNode* del = phead->next;
	del->next->prev = phead;
// 删除节点
	free(del);
	del = NULL;

}
// 查找
ListNode* Select(ListNode* phead,Datatype x) {
	ListNode* pcur = phead->next;
	while (pcur != phead) {

		if (pcur->data == x) {
			return pcur;
		}
		pcur = pcur->next;
	}
	//没有找到
	return NULL;
}
// 在指定位置之后插入数据
ListNode* AfterSelect(ListNode* pos, Datatype x) {
	assert(pos);
	ListNode* newnode = CreateNode(x);
	newnode->next = pos->next;
	newnode->prev = pos;
	pos->next->prev = newnode;

	pos->next = newnode;
}
//删除指定位置pos节点
//pos的形参是一级而不是二级是因为前面的函数形参皆是一级指针 ,这样保证了接口的一致性,确保了
//                                                    他人的方便调用与解读。
void DeleteNode(ListNode * pos,ListNode* phead) {
	assert(pos && pos != phead);
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;

	free(pos);
	pos = NULL;
}
//销毁链表:
void Distory(ListNode*phead) {
	assert(phead);
	ListNode* pcur = (phead)->next;
	while (pcur != NULL) {
		ListNode* next = pcur->next;
		free(pcur);
		pcur = next;

	}
	// 此时pcur指向phead,而phead还没有被销毁
	free(phead);
	phead = NULL; //为了接口的一致性,不将形参改为ListNode**类型,
	              //则需要在调用函数后,再将实参赋值为NULL;
}

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

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

相关文章

JVM知识点总结二

参考文章&#xff1a;【Java面试题汇总】JVM篇&#xff08;2023版&#xff09;_jvm面试题2023-CSDN博客 1、说说你了解的JVM内存模型&#xff1a; JVM由三部分组成&#xff1a;类加载子系统、运行时数据区、执行引擎 JVM内存模型&#xff1a; 内存模型里的运行时数据区&#…

STM32实现硬件I2C通讯,读取MPU6050的ID号

今天学习了使用硬件I2C的方式成功读取MPU6050的ID号&#xff0c;特此记录一下过程&#xff1a; 首先需要学习的是MPU6050的初始化&#xff1a; 第一步&#xff1a;打开GPIOB的时钟&#xff08;因为I2C2的引脚10,11在GPIOB上&#xff09; 第二步&#xff1a;打开I2C2的时钟 …

LLAMA 3的测试之旅:在GPT-4的阴影下前行

Meta终于发布了他们长期期待的LLAMA 3模型&#xff0c;这是一个开源模型&#xff0c;实际上提供了一系列新的功能&#xff0c;使得模型在回答问题时表现得更好。这对AI社区来说是一个真正的里程碑事件。 Meta正在发布新版本的Meta AI&#xff0c;这是一种可以在他们的应用程序和…

用Python在PDF文档中插入单图像水印和平铺图像水印

PDF文档因其跨平台兼容性和内容保真度成为信息交换的标准载体&#xff0c;为应对版权侵犯、内容篡改以及未经授权的传播等风险&#xff0c;向PDF中插入图片水印成为一种强化文档安全性、彰显所有权及实施访问控制的有效手段。图片水印不仅能以直观的方式标示文档来源、强化版权…

Git学习笔记(三)Git分支

Git分支是Git中非常重要的一个概念&#xff0c;无论是个人开发还是多人协作中&#xff0c;分支都起着至关重要的作用。几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离 开来进行重大的Bug修改、开发新的功能&#xff0c;以免影响…

Discuz! X3.4 升级至 Discuz! X3.5 详细教程

第一步&#xff1a;从其他以前的 Discuz! X 版本升级Discuz! X3.4 请先升级到Discuz! X3.4&#xff0c;升级教程网上比较普遍&#xff0c;在此不再论述。 第二步&#xff1a;Discuz! X3.4 升级至 Discuz! X3.5 &#xff08;Discuz 从 X3.5 以后&#xff0c;不在发布GBK版本&…

K8S基础概念

一、MASTER Kubernetes里的Master指的是集群控制节点&#xff0c;在每个Kubernetes集群里都需要有一个Master来负责整个集 群的管理和控制&#xff0c;基本上 Kubernetes的所有控制命令都发给它&#xff0c;它负责具体的执行过程&#xff0c;我们后 面执行的所有命 令基本都…

测试数据整理--chatgpt 构造sql语句导出数据库数据

在测试过程中&#xff0c;我们有时候需要准备一些测试数据&#xff0c;若从系统中直接导出Excel数据&#xff0c;数据往往庞大且需要整合&#xff0c;不好整理&#xff0c;于是我们直接去数据库中查询一些表&#xff0c;数据整合后直接导出结果会更方便。 我们今天就 用 chatg…

云原生Kubernetes: K8S 1.29版本 部署Jenkins

目录 一、实验 1.环境 2.K8S 1.29版本 部署Jenkins 服务 3.jenkins安装Kubernetes插件 二、问题 1.创建pod失败 2.journalctl如何查看日志信息 2.容器内如何查询jenkins初始密码 3.jenkins离线安装中文包报错 4.jenkins插件报错 一、实验 1.环境 &#xff08;1&…

npm最新淘宝镜像站已经更新registry(2024-04-19)

1、npm替换地址 旧的 https://registry.npm.taobao.org 已替换为 https://registry.npmmirror.com 淘宝镜像的淘宝官方提供的方法&#xff08;最新的源配置&#xff09; npm config set registry https://registry.npmmirror.com 镜像站网址&#xff1a; npmm…

ELK日志采集系统

1.什么是ELK ELK 是一套流行的数据搜索、分析和可视化解决方案&#xff0c;由三个开源项目组成&#xff0c;每个项目的首字母合起来形成了“ELK”这一术语&#xff1a; Elasticsearch (ES): Elasticsearch 是一个基于 Apache Lucene 构建的分布式、实时搜索与分析引擎。它能够…

小程序AI智能名片S2B2C商城系统:做内容、造IP、玩社群打造私域流量的新营销秘籍

在数字化浪潮汹涌的新时代&#xff0c;小程序AI智能名片S2B2C商城系统正以其独特的魅力&#xff0c;引领着营销领域的新变革。这套系统不仅将人工智能与小程序技术完美结合&#xff0c;更通过创新的S2B2C模式&#xff0c;为企业打开了一扇通往成功的大门。 面对激烈的市场竞争&…

Jenkins 的构建时执行时间问题

我们希望我的项目能够在特定的时间自动执行&#xff0c;我们需要设定一个定时任务。 Jenkins 的定时任务是通过 Cron 任务来实现的&#xff0c;但是由有点不一样。 H/2 * * * * 比如说上面的设置就是每 2 分钟执行一次。 希望每分钟执行一次 Jenkins 的每分钟执行一次的设置…

c++头文件string函数的用法

目录 前言&#xff1a; 字符串截取 字符串插入与替换 字符串区间删除 字符串排序与相加和查找 如后续需文字描述&#xff0c;&#xff0c;请评论区告诉我&#xff0c;我看到后会进行添加一些文字描述。 前言&#xff1a; 因本人女朋友在学习c过程中在一些知识网页上学了st…

uni-app中页面生命周期与vue生命周期的执行顺序对比

应用生命周期 uni-app 支持如下应用生命周期函数&#xff1a; 函数名说明平台兼容onLaunch当uni-app 初始化完成时触发&#xff08;全局只触发一次&#xff09;&#xff0c;参数为应用启动参数&#xff0c;同 uni.getLaunchOptionsSync 的返回值onShow当 uni-app 启动&#x…

09 MySQL--操作真题

1. 用一条 SQL 语句&#xff0c;查询出每门课程都大于 80 分的人。 分析&#xff1a; 去重查询出存在课程小于 80 分的人&#xff0c;设为集合A查询不在集合 A 中的人 # 第一步&#xff1a;找小于等于80分的学员姓名 select distinct name from t_student where fenshu <…

跨境电商指南:防关联浏览器和云主机有什么区别?

跨境电商的卖家分为独立站卖家和平台卖家。前者会自己开设独立站点&#xff0c;比如通过 shopify&#xff1b;后者则是入驻亚马逊或 Tiktok 等平台&#xff0c;开设商铺。其中平台卖家为了扩大收益&#xff0c;往往不止开一个店铺&#xff0c;或者有店铺代运营的供应商&#xf…

记一次中间件宕机以后持续请求导致应用OOM的排查思路(server.max-http-header-size属性配置不当的严重后果)

一、背景 最近有一次在系统并发比较高的时候&#xff0c;数据库突然发生了故障&#xff0c;导致大量请求失败&#xff0c;在数据库宕机不久&#xff0c;通过应用日志可以看到系统发生了OOM。 二、排查 初次看到这个现象的时候&#xff0c;我还是有点懵逼的&#xff0c;数据库…

解决方案ImportError: cannot import name ‘BertTokenizerFast‘ from ‘transformers‘

文章目录 一、现象二、解决方案 一、现象 从transformers 库调用该包的时候 from transformers import BertTokenizer, AdamW, BertTokenizerFast报错显示 ImportError: cannot import name ‘BertTokenizerFast’ from ‘transformers’ 二、解决方案 追溯查看transforme…

人工智能论文GPT-3(1):2020.5 Language Models are Few-Shot Learners;摘要;引言;scaling-law

摘要 近期的工作表明&#xff0c;在大量文本语料库上进行预训练&#xff0c;然后针对特定任务进行微调&#xff0c;可以在许多NLP任务和基准测试中取得实质性进展。虽然这种方法在架构上通常是与任务无关的&#xff0c;但仍然需要包含数千或数万示例的针对特定任务的微调数据集…
最新文章