数据结构:线性表(详解)

线性表

线性表的知识框架:

线性表的定义:

线性表是具有相同数据类型的n(n > 0)个数据元素的有限序列,当n = 0时线性表为一个空表。
若用L命名为线性表,则
数据集合为L= {a1,a2,…,an},其中a1称为表头元素,an称为表尾元素。除第一个元素外,每个元素有且仅有一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后继。

线性表的特点:

1.表中元素的个数有限
2.表中元素具有逻辑上的顺序表,表中元素有其先后次序
3.表中元素都是数据元素,每个元素都是单个元素
4.表中元素的数据类型相同,所以每个元素占有相同大小的存储空间
5.线性表是一种逻辑结构,表示元素之间一对一的相邻关系。顺序表和链表是指存储结构

线性表的顺序存储结构

顺序表的的定义:

线性表的顺序存储又称顺序表。它是用一组地址连续的存储单元依次存储线性表中的数据元素。

顺序表的特点:

1.顺序表的存储密度高,每个结点只存储数据结构。
2.顺序表逻辑上相邻的元素在物理上也相邻,所以插入和删除操作需要移动大量数据
3.顺序表是随机访问,即通过首地址和元素序号可在时间O(1)内找到指定的元素

顺序表代码实现:

    顺序表储存结构:

typedef int SLTDataType;
typedef struct SeqList
{
	SLDatatype capacity;//数组的容量
	SLDatatype size;//有效数据
	SLDatatype* arr;
}SL;
顺序表所有接口:
//初始化/销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDatatype x);
void SLPushFront(SL* ps, SLDatatype x);

//顺序表的头部/尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置之前插入数据/删除指定位置数据
void SLInsert(SL* ps, SLDatatype pos, SLDatatype x);
void SLErase(SL* ps, SLDatatype pos);
顺序表初始化和销毁:
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

顺序表输出:

void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
    printf("\n");
}
顺序表扩容:
void SLIncreaseCapacity(SL* ps)
{
	if (ps->capacity == ps->size)//当有效数据与实际数据相等则需要扩容
	{
		SLDatatype NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, NewCapacity * sizeof(int));
		if (tmp == NULL)
		{
			perror("malloc error");
			exit(-1);
		}
		ps->arr = tmp; //仅当 SL 结构被销毁时,用于 ps->arr 的内存才会被释放。
		ps->capacity = NewCapacity;
	}
}
顺序表尾插:
void SLPushBack(SL* ps, SLDatatype x)
{
	assert(ps);
SLIncreaseCapacity(ps);//判断是否需要扩容
ps->arr[ps->size++] = x;
}

顺序表尾插输出:

顺序表头插:
void SLPushFront(SL* ps, SLDatatype x)
{
	assert(ps);
SLIncreaseCapacity(ps);//判断是否需要扩容
for (int i = ps->size; i > 0; i--)
{
	ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}

顺序表头插输出:

顺序表尾删:
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);//判断数组是否为空
	ps->size--;//size--只是在逻辑层面删除了而已,但物理层面还是实际存在的 
               //只是我们不将它看成 顺序表的一部分,所以就可以理解为删除了         
}

顺序表尾删输出:

顺序表头删:
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

顺序表头删输出:

在指定位置插入:
void SLInsert(SL* ps, SLDatatype pos, SLDatatype x)
{
	assert(ps);
	SLCheckCapacity(ps);
	assert(pos >= 0 && pos < ps->size);//pos如果小于0那就没什么意义并且不能等于ps->size如果等于那就相当于尾插了
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

指定位置输出:

在指定位置删除:
void SLErase(SL* ps, SLDatatype pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

指定位置输出:

顺序表的优缺点:

  优点:1.空间利用率高

             2.插入删除方便

             3.结构简单

  缺点:1.访问效率低

            2.插入和删除操作可能导致元素移动

            3.难以实现部分元素的随机访问

线性表的链式存储结构:

单链表的定义:

单链表(SLL)是一种由节点序列组成的链接数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。单链表以其简单性和效率而闻名,广泛应用于各种应用程序。                                                                                  单链表结构如下:

单链表代码实现:

单链表存储结构:
typedef int SLTDataType;
typedef struct SList
{
	struct SList* next;//指针域
	SLTDataType data;//数据域
}SL;
单链表所有接口:

//链表的输出、销毁
void SLPrint(SL* phead);
void SListDesTroy(SL** pphead);

//链表的尾插、头插
void SLPushBack(SL** pphead, SLTDataType x);
void SLPushFront(SL** pphead, SLTDataType x);

//链表的尾删、头删
void SLPopBack(SL** pphead);
void SLPopFront(SL** pphead);

//查找
SL* SLTFind(SL* phead, SLTDataType x);

//在指定位置之前插入数据、之后插入数据
void SLTInsert(SL** pphead, SL* pos, SLTDataType x);
void SLTInsertAfter(SL* pos, SLTDataType x);

//删除pos节点、pos之后的节点
void SLTErase(SL** pphead, SL* pos);
void SLTEraseAfter(SL* pos);
单链表输出:

void SLPrint(SL* phead)
{
	SL* pur = phead;
	while (pur)
	{
		printf("%d->", pur->data);
		pur = pur->next;
	}
	printf("NULL");
	printf("\n");
}
单链表销毁:

void SListDesTroy(SL** pphead)
{
	void SListDesTroy(SL** pphead)
{
	assert(pphead && *pphead);
	SL* Pfast = (*pphead)->next;
	SL* Pslow = *pphead;
	while (Pslow && Pfast != NULL)
	{
		free(Pslow);
		Pslow = NULL;

		Pslow = Pfast;
		Pfast = Pfast->next;
	}
    //销毁尾节点
	free(Pslow);
	Pslow = NULL;
    //free完之后再将头节点置为空
	*pphead = NULL;
}
}

销毁链表输出:

扩容单链表空间:

SL* SLTBuyNode(SLTDataType x)
{
	SL* Newnode = (SL*)malloc(sizeof(SL));
	SL*	ptmp = Newnode;
	if (ptmp == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
	Newnode->data = x;
	Newnode->next = NULL;
	return Newnode;
}
单链表尾插:

//为什么需要二级指针而不用一级指针呢,因为传一级的话改变不了它的指向而二级指针可以
//就相当于C语言里面传值和传地址一个道理
void SLPushBack(SL** pphead, SLTDataType x)
{
	//pphead:相当于指针指向节点的那个指针的地址
    //*pphead:相当于节点地址
    //**pphead:相当于节点里的数据
	assert(pphead);//判断pphead指针是否为空和节点是否为空
	//assert(*pphead);//判断pphead节点是否为空
	SL* newnode = SLTBuyNode(x);
	if (*pphead == NULL)//当链表为空时那么newnode就可以作为链表的新节点
	{
		*pphead = newnode;
		return;
	}
	//链表不为空
	SL* Ptmp = *pphead;
	while (Ptmp->next)
	{
		Ptmp = Ptmp->next;
	}
	Ptmp->next = newnode;
}

单链表尾插输出:

本质上,单指针用于“只读”操作,而双指针用于“读写”操作。

以下是一个简化的类比来说明区别:

想象一个链表就像一列火车车厢。每个车厢代表列表中的一个节点,车厢之间的连接代表指针。

单指针就像火车上的乘客。他们可以从一辆车厢移动到另一辆车厢,观察每辆车厢的内容(数据访问),但他们不能直接拆卸或连接车厢(修改列表结构)。

双指针就像火车乘务员。他们不仅有权在车厢之间移动,还可以解耦和耦合车厢,修改列车的组成(修改列表结构)。
如果还是搞不懂可以点开这个链接,这个博主写的非常好http://t.csdnimg.cn/yNoDo

单链表头插:

void SLPushFront(SL** pphead, SLTDataType x)
{
	assert(pphead);
	SL* newnode = SLTBuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
		return;
	}
	newnode->next = *pphead;
	*pphead = newnode;
}

单链表头插输出:

单链表尾插:


void SLPopBack(SL** pphead)
{
	assert(pphead && *pphead);//判断pphead指针是否为空和节点是否为空
	//只有一个节点
	//因为->符号的优先级比*符号的优先级高所以不加括号就是pphead->next
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//多个节点
	SL* Pfast = *pphead;
	SL* Pslow = NULL;
	//如果是用Pfast去判断的话那等while结束的时候到它会指向NULL,Plast会指向最后一个节点
    //最后我们是把NULL赋给Pfast->next以此来达到尾删的效果,那这样都不是删除最后一个节点而是给NULL赋NULL。
	//所以是要用Pfast->next去进行判断
	while (Pfast->next)
	{
		Pslow = Pfast;
		Pfast = Pfast->next;
	}
	Pslow->next = NULL;
	//最后别忘记销毁尾节点
	free(Pfast);
	Pfast = NULL;
}

单链表尾删输出:

单链表头删:

void SLPopFront(SL** pphead)
{
	assert(pphead && *pphead);
	//只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//多个节点
	SL* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

单链表头删输出:

单链表查找:

SL* SLTFind(SL* phead, SLTDataType x)
{
	assert(phead);
	SL* Pcur = phead;
	while (Pcur)
	{
		if (Pcur->data == x)
		{
			return Pcur;
		}
		Pcur = Pcur->next;
	}
	return NULL;
}

查找输出:

在指定位置之前插入数据:
void SLTInsert(SL** pphead, SL* pos, SLTDataType x)
{
	assert(pphead && *pphead);
	assert(pos);//判断pos指针是否为空
	SL* newnode = SLTBuyNode(x);//扩容一个新节点
	//假设pos为头节点
	if (pos == *pphead)
	{   //头插
		SLPushFront(pphead , x);
		return;//插入完新数据直接return
	}
	SL* Pur = *pphead;
	//不为头节点
	while (Pur)
	{
		if (Pur->next == pos)
		{
			Pur->next = newnode;
			newnode->next = pos;
		}
		Pur = Pur->next;
	}
	return;
}

指定位置之前输出:

在指定位置之后插入数据:

//尾插不需要pos之前的指针,所以pphead在这里不起作用
void SLTInsertAfter(SL* pos, SLTDataType x)
{
	assert(pos);
	SL* newnode = SLTBuyNode(x);
	SL* Ptur = pos->next;//防止找不到它的下一个节点
	pos->next = newnode;
	newnode->next = Ptur;
}

指定位置之后输出:

删除pos指针:
void SLTErase(SL** pphead, SL* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	//pos刚好是头结点,执行头删
	if (*pphead == pos) 
	{
		//头删
		SLPopFront(pphead);
		return;
	}
	SL* Pur = *pphead;
	//不为头节点
	while (Pur->next != pos)
	{
		Pur = Pur->next;
	}
	Pur->next = pos->next;
	free(pos);
	pos = NULL;
	return;
	//为什么错误?上面为什么对?
	//因为上面就是他先把pos置为空但是那个循环不会结束等到Pur->NULL时
	//那这又与pos相等了,如果再去访问pos->next就会报错
	//访问空指针的next就会出问题但是访问有效指针的next且那个next为空这样并不会报错
	/*while (Pur)
	{
		if (Pur->next == pos)
		{
			Pur->next = pos->next;
			free(pos);
			pos = NULL;
		}
		Pur = Pur->next;
	}*/
}

删除pos指针输出:

删除pos之后节点
void SLTEraseAfter(SL* pos)
{
	assert(pos);
	SL* Pur = pos->next;//保存Pur节点等下需要销毁这个节点
	pos->next = pos->next->next;
	free(Pur);
	Pur = NULL;
}

删除pos之后节点输出:

                                     上述代码全部都是用不带头节点编写而成 

单链表的优缺点:

 优点:
             1.简单易懂
             2.插入和删除操作高效
             3.动态内存管理

缺点:
             1.无法随机访问
             2.插入操作会破坏原有顺序
             3.无法向后遍历

双链表的定义:

在计算机科学中,双链表(DLL)是一种由元素序列组成的链接数据结构,每个元素称为节点,每个节点都有两个指针:一个指向序列中的下一个节点,另一个指向前面的节点。每个节点还包含一个数据元素。

双链表代码实现:

双链表存储结构:
typedef int LTDataType;
typedef struct DList
{
	struct DList* next;//后继节点
	struct DList* prev;//前驱节点
	LTDataType data;//节点数据
}DL;
双链表所有接口:
//初始化、销毁、输出
void LTInit(DL** pphead);
void LTDesTroy(DL** pphead);
void LTPrint(DL* phead);

//尾插、头插
void LTPushBack(DL* phead, LTDataType x);
void LTPushFront(DL* phead, LTDataType x);

//头删、尾删
void LTPopBack(DL* phead);
void LTPopFront(DL* phead);

//查找
DL* LTFind(DL* phead, LTDataType x);

//在pos位置之后插入数据、删除pos位置的数据
void LTInsert(DL* pos, LTDataType x);
void LTErase(DL* pos);
双链表初始化:
void LTInit(DL** pphead)
{
	*pphead = (DL*)malloc(sizeof(DL));//为哨兵位开辟空间
	if (*pphead == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
    //双链表节点的初始化是前驱和后继指针都是指向自身
	(*pphead)->next = (*pphead)->prev = *pphead;
	(*pphead)->data = 0;
}

双链表初始化输出:

双链表销毁:
void  LTDesTroy(DL** pphead)
{
	assert(pphead);
	assert(*pphead);
	DL* Pfast = (*pphead)->next->next;
	DL* Pslow = (*pphead)->next;
	while (Pslow != NULL)
	{
		free(Pslow);
		Pslow = NULL;
		Pslow = Pfast;
		Pfast = Pfast->next;
	}
	free(*pphead);
	*pphead = NULL;
}

双链表销毁输出:

扩展双链表空间:
DL* DLTBuyNode(LTDataType x)
{
	DL* NewNode = (DL*)malloc(sizeof(DL));//为新节点开辟空间
	DL* Ptmp = NewNode;
	if (Ptmp == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
	Ptmp->data = x;
	Ptmp->next = Ptmp->prev = NewNode;
	return NewNode;
}
双链表输出:
void LTPrint(DL* phead)
{
	assert(phead);
	DL* Pur = phead->next;//因为哨兵位没有数据所以不需要遍历它
	while (Pur != phead)
	{
		printf("%d->", Pur->data);
		Pur = Pur->next;
	}
	printf("\n");
}
双链表尾插:
void LTPushBack(DL* phead, LTDataType x)
{
    assert(phead);//判断phead指针是否为空
	DL* Newnode = DLTBuyNode(x);
	//先改变新节点
	Newnode->next = phead;//让新节点的后继指针指向头节点(原先是尾节点指向哨兵位的前驱)
	Newnode->prev = phead->prev;//让新节点的前驱指针指向尾节点

	//再改变尾节点
	phead->prev->next = Newnode;//让尾节点的后继指针指向新节点
	phead->prev = Newnode;//哨兵位的前驱指针指向新节点
}

双链表尾插输出:

双链表头插:
//双链表的头插并不是在哨兵位之前插入数据而是第一个有效节点之前插入
//在哨兵位之前插入数据就相当尾插,因为哨兵位前面就是最后一个有效节点
void LTPushFront(DL* phead, LTDataType x)
{
	assert(phead);
	DL* Newnode = DLTBuyNode(x);
	//先改变新节点的指向
	Newnode->next = phead->next;
	Newnode->prev = phead;

	phead->next->prev = Newnode;
	phead->next = Newnode;
}

双链表头插输出:

双链表尾删:
void LTPopBack(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);//哨兵位指向自己就相当于双链表为空
	DL* pre = phead->prev;
	//先让尾节点的前一个节点的next指向哨兵位再让哨兵位的前驱指针指向尾节点的前一个节点那这样下 
    //来尾节点就相当于被销毁了
	phead->prev->prev->next = phead;//phead->prev就相当于尾节点然后phead->prev->prev就相当 
                                    //于尾节点的前一个节点
	phead->prev = phead->prev->prev;
	free(pre);
	pre = NULL;
	
}

双链表尾删输出:

双链表头删:
void LTPopFront(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);
	DL* next = phead->next;//如果不先保存原哨兵位的next地址那删除完节点后再去 
                           //free(phead>next)这样就是删除新头节点了并不是再删除旧的头节点
	phead->next->next->prev = phead;
	phead->next = phead->next->next;
	free(next);
	next = NULL;
}

双链表头删输出:

双链表查找:
DL* LTFind(DL* phead, LTDataType x)
{
	assert(phead);
	DL* Pur = phead->next;//区别于与单链表的是这里传的并不是头节点而是头节点next
	while (Pur != phead)
	{
		if (Pur->data == x)
		{
			return Pur;
		}
		Pur = Pur->next;
	}
	return NULL;
}

双链表查找输出:

在指定位置之后插入数据:
void LTInsert(DL* pos, LTDataType x)
{
	assert(pos);
	DL* Newnode = DLTBuyNode(x);
	//依然是先修改新节点的指向
	Newnode->next = pos->next;
	Newnode->prev = pos;

	//不能先改变pos->next的指向因为修改了就找不到pos后面的节点
	//所以指向先改变pos后面节点的指向然后再改变pos的指向
	pos->next->prev = Newnode;
	pos->next = Newnode;
	
}

在指定位置之后插入数据输出:

删除pos位置的数据:
void LTErase(DL* pos)
{
	assert(pos);
	//先改变pos前面的节点那就找不到pos后面的节点,所以只能先改变后面再改变前面
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
}

删除pos位置的数据输出:

链表与顺序表的比较:

1.结构:

链表: 链表由一系列节点组成,每个节点包含数据元素和指向下一个节点的指针。节点之间的连接是通过指针实现的,因此链表是一种非连续的存储结构

顺序表顺序表将元素存储在连续的内存空间中,每个元素占用一个固定大小的单元。元素之间的访问通过索引实现,因此顺序表是一种连续的存储结构

2.逻辑结构与物理结构:

采用顺序存储时,逻辑上相邻的元素,对应的物理存储位置也相邻。而采用链式存储时,逻辑上相邻的元素,物理存储位置不一定相邻,对应的逻辑关系时通过指针链接来表示的。

3.遍历、插入、删除操作:

插入:在链表中插入新元素,需要修改相邻节点的指针以保持链表的顺序。在顺序表中插入新元素,如果空间不足则需要重新分配内存或移动现有元素。

删除:在链表中删除元素,需要修改相邻节点的指针以跳过被删除的元素。在顺序表中删除元素,需要将被删除元素后面的元素向前移动一个位置。

遍历在链表中遍历元素,需要逐个遍历节点并访问数据元素。在顺序表中遍历元素,可以使用循环访问每个元素

4.应用:

链表: 适用于需要频繁插入和删除操作的情景,因为链表的插入和删除操作效率较高,且不需要预先分配固定数量的内存空间。例如,缓存实现、栈和队列的底层实现等。

顺序表: 适用于需要随机访问数据的情景,因为顺序表的随机访问效率较高,可以直接通过索引访问任意位置的元素。例如,数组的底层实现、符号表等。

总结:

在选择数据结构时,需要根据具体应用场景权衡利弊。如果需要频繁插入和删除操作,并且对随机访问性能要求不高,则链表是一个不错的选择。如果需要随机访问数据,并且插入和删除操作不频繁,则顺序表是一个更好的选择。

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

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

相关文章

【方法】如何创建RAR格式压缩文件?

为了方便存储或者传输文件&#xff0c;我们经常会把文件打包成不同格式的压缩包&#xff0c;那如果想创建的是RAR格式的压缩包&#xff0c;要如何做呢&#xff1f; RAR是WinRAR软件独有的压缩格式&#xff0c;所以我们可以通过WinRAR软件来创建RAR格式压缩包。下面分享两种创建…

02_SpringBoot程序快速启动

目录 打包命令启动启动成功测试结果 打包 点击package打包命令&#xff0c;会生成target目录&#xff0c;目录下会有生成的jar包 命令启动 打开cmd命令窗口&#xff0c;进入子项目的target目录下,输入命令后&#xff0c;回车… java -jar .\note-boot-core-1.0-SNAPSHOT.j…

一起深度学习

CIFAR-10 卷积神经网络 下载数据集构建网络运行测试 下载数据集 batchsz 32cifar_train datasets.CIFAR10(data,trainTrue,transformtorchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),torchvision.transforms.ToTensor()]),downloadTrue)cifar_train …

电脑录屏什么软件好?网友力荐的3款软件!

随着电脑的使用越来越广泛&#xff0c;电脑录屏软件也成为了人们日常生活中经常需要使用到的工具。无论是录制游戏画面、教程演示还是远程教育&#xff0c;一款优秀的电脑录屏软件都能为用户提供极大的帮助&#xff0c;可是电脑录屏什么软件好呢&#xff1f;本文将为大家介绍3款…

图形存储与处理在AI去衣技术中的关键角色

引言&#xff1a; 随着人工智能技术的不断进步&#xff0c;AI去衣技术作为一种颇具争议的应用&#xff0c;已经引起了广泛的关注。该技术依托于深度学习、计算机视觉等领域的先进成果&#xff0c;通过分析图像内容实现对人物衣物的识别和去除。在这一过程中&#xff0c;图形存储…

repo跟git的关系

关于repo 大都讲的太复杂了,大多是从定义角度跟命令角度去讲解,其实从现实项目使用角度而言repo很好理解. 我们都知道git是用来管理项目的,多人开发过程中git功能很好用.现在我们知道一个项目会用一个git仓库去管理,项目的开发过程中会使用git创建分支之类的来更好的维护项目代…

stateflow绝对时间逻辑实操

使用after运算符替换at运算符 如果将at运算符与绝对时间-时间逻辑一起使用,则在尝试模拟模型时会出现错误消息。请改用after运算符。 假设您想使用(5.33,秒)的转换来定义时间延迟。 将转换更改为after(5.33秒),如图所示。这样就不报错了。 使用带有后运算符的外部自循…

【源码+文档+安装教程】校园社团信息管理系统

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了校园社团信息管理系统的开发全过程。通过分析校园社团信息管理系统管理的不足&#xff0c;创建了一个计算机管理校园社团信息管理系统的方案。文章介绍了校园社团…

【EasySpider】EasySpider+mysql执行配置异常

问题 使用易采集工具操作时候&#xff0c;遇到一个执行异常&#xff0c;后来发现没有选择数据类型 Loading stealth.min.js MySQL config file path: ./mysql_config.json 成功连接到数据库。 Successfully connected to the database. Traceback (most recent call last):…

做了两年数仓,积累的12条SQL调优技巧

本文是作者本人做数仓调优时&#xff0c;所经常使用的SQL调优技巧&#xff0c;这些“技巧”也是经过日常不断摸索、问题排查以及网络检索并且经过本人在线上大规模使用过的&#xff0c;对于下面这12条&#xff08;不算多&#xff0c;但特别有用&#xff09;调优小“技巧”&…

[qnx] 通过zcu104 SD卡更新qnx镜像的步骤

0. 概述 本文演示如果给Xlinx zcu104开发板刷入自定义的qnx镜像 1.将拨码开关设置为SD卡启动 如下图所示&#xff0c;将1拨到On,2,3,4拨到Off&#xff0c;即为通过SD启动。 2.准备SD卡中的内容 首先需要将SD格式化为FAT32的&#xff08;如果已经是FAT32格式&#xff0c;则…

Python高级编程-DJango1

Python高级编程 灵感并不是在逻辑思考的延长线上产生 而是在破除逻辑或常识的地方才有灵感 目录 Python高级编程 1.python学习之前的准备 ​编辑 2.DJango 开发网站 3.创建项目 4.&#xff44;&#xff4a;&#xff41;&#xff4e;&#xff47;项目结构介绍 &#xff11;&…

转行HiL测试工程师

转行没方向&#xff1f;0基础也能转新能源汽车HiL测试岗位&#xff01; 都2024年了&#xff0c;不会还有同学想往软件测试、车载测试方向转吧&#xff01;996、卷经验、卷待遇… ❓❓❓❓想转行没有方向&#xff1f; 建议选择发展前景好的行业&#xff0c;转行前先找好行业&…

目标检测——打架视频数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

C++ | Leetcode C++题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int m matrix.size();int n matrix[0].size();int flag_col0 false;for (int i 0; i < m; i) {if (!matrix[i][0]) {flag_col0 true;}for …

【Markdown笔记】——扩展语法学习part3 表格脚注标题编号(锚点)列表删除线人物列表(todo列表)emoji等

【Markdown笔记】——扩展语法学习part3 表格&脚注等 MarkdownMarkdown 表格语法表格内容居中、左对齐、右对齐 Markdown 脚注语法Markdown 标题编号语法Markdown 列表语法Markdown 删除线语法Markdown 任务列表语法Markdown 使用 Emoji 表情 前几篇markdown相关博客&#…

基于 Spring Boot 博客系统开发(七)

基于 Spring Boot 博客系统开发&#xff08;七&#xff09; 本系统是简易的个人博客系统开发&#xff0c;为了更加熟练地掌握 SprIng Boot 框架及相关技术的使用。&#x1f33f;&#x1f33f;&#x1f33f; 基于 Spring Boot 博客系统开发&#xff08;六&#xff09;&#x1f…

2024年第十三届工程与创新材料国际会议(ICEIM 2024)即将召开!

2024年第十三届工程与创新材料国际会议&#xff08;ICEIM 2024&#xff09;将于2024年9月6-8日在日本东京举行。ICEIM 2024由东京电机大学主办&#xff0c;会议旨在材料科学与工程、材料特性、测量方法和应用等相关领域进行学术交流与合作&#xff0c;在材料的微观世界里&#…

异或的使用在机器人项目上的应用||位运算符在智能驾驶项目上的应用

目录 一、异或的使用在机器人项目上的应用 二、异或&#xff08;XOR&#xff09;操作的几个特点 三、位运算符在智能驾驶项目上的应用 一、异或的使用在机器人项目上的应用 在当时负责皮带机器人项目中&#xff0c;就有一个很好的应用。此时需要设置电机驱动模块、编码器驱动…

Leetcode—724. 寻找数组的中心下标【简单】

2024每日刷题&#xff08;129&#xff09; Leetcode—724. 寻找数组的中心下标 实现代码 class Solution { public:int pivotIndex(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);int prefix 0;for(int i 0; i < nums.size(); i) {i…