链表的介绍
目录
- 引言
- 优缺点
- 与链表相似的数据结构
- 注意事项
- 单向链表的实现
- 基础实现
- 创建类
- 创建成员变量
- 创建特殊方法
- 增加数据
- push_back方法
- insert方法
- 删除数据
- del_back方法
- del_index方法
- clear方法
- 查询数据
- at方法与重载的中括号运算符
- toArray方法
- indexOf方法
- 修改数据
- 获取链表大小
- 测试方法是否正常
- 总结
- 下篇预告
引言
大家好,我是链表。我呢,是一种存储非连续性数据的物理数据结构,我的每一个数据都用一个个节点来存储,我的每一个节点都用一条条的“链”来链接,因此,就被后人称作链表了。
优缺点
其中,我增加数据和删除数据的时间复杂度最坏是O(n)
,因为增加数据的话,就只要让我的最后一个节点接上存储新数据的节点就行了。而删除数据的话,就只要让我倒数第二个节点断开跟我最后一个节点的链接就行了。
虽然我非常擅长这些,但我也有一些坏的地方,如查询数据和修改数据,时间复杂度最好是O(n)
,查询的话,就需要让我遍历每一个节点,然后分别对每一个节点判断,才行;而修改的话,其实就是跟我查询数据的操作差不多,也是要先让我遍历每一个节点,然后分别对每一个节点判断才行。
与链表相似的数据结构
而与我相似的数据结构呢,有双向链表,有循环链表,还有他们俩的结合体——双向循环链表,跟C++里的STL容器list
差不多。其中,我们将要实现的是单向链表,也就是我,如果你不知道它们长什么样的话,就看下下面的图片吧。
注意事项
不要用节点对象的引用去定位节点,因为这会让我的节点莫名消失!在实际用C/C++实现非连续性存储数据的数据结构的时候至关重要!
单向链表的实现
基础实现
创建类
首先,要想实现我,就需要两个模板类,一个是节点类,一个是单向链表类。
template<class T>
class mylist {
private:class node {public:T t;node* next;node(const T t = NULL, node* nextTo = nullptr) {this->t = t;this->next = nextTo; }};
};
创建成员变量
然后,就要给这个单向链表类增加表示大小的成员变量ic
和我的“头”——头结点head
了。
template<class T>
class mylist {
private:class node {public:T t;node* next;node(const T t = NULL, node* nextTo = nullptr) {this->t = t;this->next = nextTo;}};int ic;node* head;
};
创建特殊方法
最后,在单向链表类里,我们需要做许多特殊的方法,分别是无参构造方法,数组构造方法,拷贝构造方法,重载赋值运算符和析构方法,其中,析构方法不用递归实现的话对我来说太复杂了,因此,就需要一个助于让我们析构的临时私有方法deletenode
方法来销毁我。至此,这些特殊方法做完之后,我们就要准备要创建并实现我增加数据的方法了。
#pragma once
#include <iostream>
using namespace std;
template<class T>
class mylist {
private:class node {public:T t;node* next;node(const T t = NULL, node* nextTo = nullptr) {this->t = t;this->next = nextTo;}};unsigned int ic;node* head;void deletenode(node*& delnode) {if (nullptr != delnode->next) {deletenode(delnode->next);}delnode->next = nullptr;delete delnode;}T* arr;
public:mylist() {this->ic = 0;this->head = new node;}mylist(T* array, const unsigned int isize) {this->ic = isize;this->head = new node;node** addnode = &this->head;for (int i = 0; i < isize; i++) {(*addnode)->next = new node(array[i]);addnode = &(*addnode)->next;}}mylist(const mylist& list) {this->ic = list.ic;this->head = new node;*this = list;}mylist& operator=(const mylist& list) {node* searchnode = list.head;node** addnode = &this->head;while (nullptr != searchnode->next) {searchnode = searchnode->next;(*addnode)->next = new node(searchnode->t);addnode = &(*addnode)->next;}return *this;}~mylist() {deletenode(this->head);}
};
增加数据
增加数据的方法呢,有两个,一个是push_back
方法,一个是insert
方法。
push_back方法
其中,push_back
方法用于在我的最后一个节点插入存放新数据的节点,因此,push_back
方法的形参就是要插入的新数据。实现它时,首先要创建一个指向我的头结点的节点对象的指针tailnode
,用于定位我的最后一个节点,然后,用一个while
循环将这个节点对象指针移到在我的“链”上的下一个节点的地址上,以此类推,最终会使这个节点对象指针定位到我的最后一个节点的地址上,最后,在定位好后,new
出来一个节点,这个新节点的值为push_back
方法中传入的新数据形参,并让tailnode
这个节点指针指向的节点的下一个节点为这个刚new
出来的新节点,以此让这个新节点在我的“链”上。之后呢,我的大小自增1,并返回这个新数据,因为这个新数据是泛型的,所以返回的类型就为T
。
T push_back(const T item) {node** addnode = &this->head;while (nullptr != (*addnode)->next) {addnode = &(*addnode)->next;}(*addnode)->next = new node(item);this->ic++;return item;
}
insert方法
而insert
方法,则用于在我的其中一个节点之前插入存放新数据的节点,跟push_back
方法的用途差不多,返回的类型都是泛型T
,只不过插入的位置的形参变了。形参呢,除了要插入的新数据之外,还有索引index
;位置呢,很随便,哪里都可以插。但需要注意的是,这个索引,它不能是负数,所以这个索引的形参的类型就只能是unsigned int
了,之后,我们在实现这个方法前,先要对这个索引形参判断一下,如果这个索引大于等于我的大小,那么就不能插入,直接返回NULL
就行,之后,我们定义指向头结点的节点指针addnode
,并通过while
循环来定位addnode
插入的位置,这里的while
循环以索引index
的值来循环,每循环一次之后就使它自减1,直到它为0为止。定位好后,就new
一个节点对象newnode
,它的值为要插入的新数据,它的下一个节点则为addnode
指向的节点的下一个节点,之后,就用这个addnode
节点指针指向的节点来连接节点对象newnode
,使其在我的同一条“链”上,就行了,然后,大小自增1,返回新数据的值,整个insert
方法也就正式完成了。
T insert(const T item, unsigned int index) {if (index >= this->ic) {return NULL;}node** addnode = &this->head;while (index--) {addnode = &(*addnode)->next;}node* newnode = new node(item, (*addnode)->next);(*addnode)->next = newnode;this->ic++;
}
接着,我们就要实现删除数据的一些方法了。
删除数据
删除数据的方法呢,我要的有三个,第一是del_back
方法,第二是del_index
方法,第三是clear
方法。
del_back方法
del_back
方法呢,无参,返回泛型T
,对应了我最后一个节点的数据,在实现这个方法之前,像insert
方法那样,也需要先判断一下,不过跟insert
方法不同的是,del_back
方法则先检测我的大小是否为0,如果是,就返回NULL
,因为我的大小为0,相当于我只有“头”可以删,我删了“头”等于我“英年早逝”,只有析构方法执行时,我老了,才能“逝”,所以直接返回NULL
,不是就继续执行,然后定义一个指向我的头结点的节点指针nextIsTailNode
,随即等它在通过while
循环移到倒数第2个节点的时候,就让它定位好了,之后,用一个类型为泛型T
的变量last
存储nextIsTailNode
指向的节点的下一个节点的值,并delete
掉节点指针nextIsTailNode
指向的节点的下一个节点——就是我的最后一个节点,让它指向的的下一个节点设为空指针,然后让我的大小自减1,最后一个节点也就彻底离开我了。
T del_back() {if (!this->ic) {return NULL;}node** nextIsTailNode = &this->head;while (nullptr != (*nextIsTailNode)->next->next) {nextIsTailNode = &(*nextIsTailNode)->next;}T last = (*nextIsTailNode)->next->t;delete (*nextIsTailNode)->next;(*nextIsTailNode)->next = nullptr;this->ic--;return last;
}
del_index方法
而del_index
方法,肯定是要有一个代表索引的类型为unsigned int
的形参index
的,如果你用指向某个节点的指针来删的话,那么这个指针所删除的节点及它后面的节点也一并不见了,相当于我骨折了。因此,我建议你们根据索引来删数据的时候,用节点指针来查找,用节点对象来存储索引所对应的节点的下一个节点及它后面的节点。而且在这个方法实现之前,除了我的大小不能为0之外,如果索引是否大于等于我的大小,也直接返回NULL
,不删,之后,根据刚才提到的建议,在后面定义一个指向头节点的节点指针searchnode
用于查找,通过while
循环执行index
次循环,让searchnode
通过一次次的转到它的下一个节点的地址来定位。之后定位好,就定义一个类型为泛型T
的变量item
来存储索引代表的节点的值,然后定义一个节点对象hasnode
为searchnode
指向的下一个节点的下一个节点及后面的所有节点,并delete
掉searchnode
节点指针指向的节点及后面的所有节点,然后让searchnode
指向的节点跟hasnode
节点对象连接一下,既能保证了数据的完整性,又使我只删除了一个节点,最后我的大小自减1,并返回变量item
的值,这个del_index
方法也实现完毕了。
T del_index(unsigned int index) {if (!this->ic || index >= this->ic) {return NULL;}node** searchnode = &this->head;while (index--) {searchnode = &(*searchnode)->next;}T item = (*searchnode)->next->t;node* hasnode = (*searchnode)->next->next;delete (*searchnode)->next;(*searchnode)->next = hasnode;this->ic--;return item;
}
clear方法
clear
方法,就跟我的析构方法差不多,只是要删的对象有差别,析构方法是包括头节点,全都要删,而clear
方法,除了头节点以外,全都要删,这就是区别。当然,如果要从头节点的下一个节点开始删的话,就要我的大小不为0才行,否则报错。之后删完全了,就给大小设为0就行了。
void clear() {if (this->ic) {this->ic = 0;deletenode(this->head->next);this->head->next = nullptr;}
}
到后面,就要开始来查询一下数据了。
查询数据
查询数据的方法呢,普通的有at
方法,与之同等的重载中括号运算符,你要是想遍历我整个“链”上的元素,也可以带上toArray
方法,你要是想查询我所存的元素在哪个节点上,这个节点又在我的哪个位置上,indexOf
方法就足够。
at方法与重载的中括号运算符
先略讲at
方法,因为at
方法的实现跟重载的中括号运算符的实现差不多,所以实现起来很简单,只需要返回重载的中括号运算符返回的值就好。现在主要就是实现重载的中括号运算符。
T& at(const unsigned int index) {return (*this)[index];
}
重载的中括号运算符,有代表索引的类型为unsigned int
的形参index
。执行这个方法时,第一步,检测一下索引是否正常,如果索引超过我的大小,就直接返回NULL
,反之就继续执行;第二步,初始化节点对象searchnode
为我头节点的下一个节点,通过index
次循环来定位,具体定位的方法前面都讲过了;第三步,也是最后一步,节点对象searchnode
定位好后,返回节点对象searchnode
的值,就行了。
T& operator[](unsigned int index) {if (index >= this->ic) {static T nulldata = NULL;return nulldata;}node* searchnode = this->head->next;while (index--) {searchnode = searchnode->next;}return searchnode->t;
}
toArray方法
实现这个方法,得先往我这个类里面定义一个将要成为动态数组的指向泛型T
类型的arr
指针,因为这将要为整个toArray
方法提供地基来“搭建”。
之后,就用一个searchnode
节点对象在我的“链”上遍历一下我的节点,并把遍历的节点一一转化成数据并输出在动态数组arr
里面,最后返回arr
这个动态数组的引用,就又好了一次。
T*& toArray() {delete[] this->arr;this->arr = new T[this->ic];node* searchnode = this->head;int i = 0;while (nullptr != searchnode->next) {searchnode = searchnode->next;this->arr[i++] = searchnode->t;}return this->arr;
}
啥?你说我的这个arr
动态数组还没有创建和析构的方式?没事,在我的所有构造方法中,可以为动态数组arr
new
一小块大小为0的内存;在析构方法中,可以delete[]
掉这个动态数组arr
,即使是大小为0的内存也原封不动地还给操作系统,就跟“借空气,还空气”差不多;在toArray
方法中,也可以前面增加这两行代码,只要有了这些必备的代码,那你的构造方法,析构方法和toArray
方法也就能放下心了,因为几乎没有任何的bug存在。在这之后,就可以去学最后一个特殊的方法——indexOf
方法了。
delete[] this->arr;
this->arr = new T[this->ic];
indexOf方法
在indexOf
方法中,只要一个形参——代表要找的数据的类型为泛型T
的item
。开始执行后,先初始化一个节点对象searchnode
为我的头结点,也可以理解成节点对象searchnode
对我1:1地进行克隆,用于遍历节点,找到数据,并初始化一个代表索引的无符号整型变量index
为0,以此来辅助这个indexOf
方法找数据,然后searchnode
节点对象遍历我的所有节点:先转到下一个节点,如果searchnode
的值为要找的数据,那么就返回这个数据所对应的节点索引——就是刚才创建过的无符号整型index
,如果不是,那么索引index
自增1,再接着遍历,直到searchnode
节点对象找到数据或者遍历完我,如果遍历完我,最后就返回-1,说明这个要找的数据并不在我的某一个节点里面。那为什么这个indexOf
方法的返回类型是long long
呢,这是我因为怕在返回-1的时候被unsigned int
转为正数,从而让用户被我误导,觉得要查找的数据在我的某一个节点上,并且unsigned int
所能存储的最大值已经超过了int
所能存储的最大值,如果以unsigned int
的最大值来访问的话,可能就会因为int
所能存储的最大值而被转换成负数。所以,就需要long long
类型来返回这个index
。好了,在indexOf
方法做好之后,接下来就继续看吧。
long long indexOf(const T item) {node* searchnode = this->head;unsigned int index = 0;while (nullptr != searchnode->next) {searchnode = searchnode->next;if (item == searchnode->t) {return index;}index++;}return -1;
}
修改数据
修改数据的话,不需要什么方法,一般修改数据的办法就是借助我的查询方法来用赋值运算符来修改值,没有什么花招。如:
List[0] = 1;//这里的“List”是一个链表对象
获取链表大小
在做好我的最后,获取链表的大小的方法也要有,如size
方法和isEmpty
方法,不然,用户怎么能查询到我的大小呢?第一是size
方法,只需要返回我的大小就行;第二是isEmpty
方法,只需要返回我的大小是否为0就行。
unsigned int size() const {return this->ic;
}
bool isEmpty() const {return 0 == this->ic;
}
测试方法是否正常
现在我的所有方法都走做好了,我们也要测试一下了。就一口气测试我的全部方法好了。
#include <iostream>
#include "mylist2.hpp"
using namespace std;int main() {mylist<int>m;//普通构造方法测试cout << "原始大小:" << m.size() << " 是否为空:" << (m.isEmpty() ? "true" : "false") << endl;//size方法与isEmpty方法测试1m.insert(1, 0);//insert方法测试1m.push_back(1);//push_back方法测试1m.push_back(2);//push_back方法测试2m.insert(3, 1);//insert方法测试2cout << "链表m增加数据后大小:" << m.size() << " 是否为空:" << (m.isEmpty() ? "true" : "false") << endl;//size方法与isEmpty方法测试2m.del_back();//del_back方法测试m.del_index(2);//del_index方法测试1m.del_index(1);//del_index方法测试2cout << "链表m删除数据后大小:" << m.size() << " 是否为空:" << (m.isEmpty() ? "true" : "false") << endl;//size方法与isEmpty方法测试3int arr[5] = { 1, 2, 3, 4, 5 };mylist<int>ma(arr, 5);//数组构造方法测试mylist<int>mb = ma;//拷贝构造方法测试const int* arra = ma.toArray();//toArray方法测试1const int* arrb = mb.toArray();//toArray方法测试2int i = 0;while (i < 5) {cout << "ma[" << i << "] == mb[" << i << "]:" << (arra[i] == arrb[i] ? "true" : "false") << endl;//toArray方法测试3i++;}cout << "ma[1] = " << ma[1] << " ma[3] == ma.at(3):" << (ma[3] == ma.at(3) ? "true" : "false") << endl;//重载中括号运算符测试1 at方法测试cout << "5 == ma[ma.indexOf(5)]:" << (5 == ma[ma.indexOf(5)] ? "true" : "false") << endl;//重载中括号运算符测试2 indexOf方法测试1cout << "ma.indexOf(7) = " << ma.indexOf(7) << " NULL == ma[-1]:" << (NULL == ma[-1] ? "true" : "false") << endl;//重载中括号运算符测试3 indexOf方法测试2m.clear();//clear方法测试cout << "链表m清空数据后大小:" << m.size() << " 是否为空:" << (m.isEmpty() ? "true" : "false") << endl;//size方法与isEmpty方法测试4return 0;
}
如果这段测试代码执行之后是这样打印的:
原始大小:0 是否为空:true
链表m增加数据后大小:3 是否为空:false
链表m删除数据后大小:1 是否为空:false
ma[0] == mb[0]:true
ma[1] == mb[1]:true
ma[2] == mb[2]:true
ma[3] == mb[3]:true
ma[4] == mb[4]:true
ma[1] = 2 ma[3] == ma.at(3):true
5 == ma[ma.indexOf(5)]:true
ma.indexOf(7) = -1 NULL == ma[-1]:true
链表m清空数据后大小:0 是否为空:true
那么,我也就完全实现好了。
总结
通过刚才实现我这个链表类的代码,我们可以知道,我增加数据的时间复杂度为O(n)
,因为要通过某一个指向节点对象的指针来定位;删除数据的时间复杂度也为O(n)
,或者以delnode
方法为例时间复杂度也为O(1)
,内存复杂度却为O(n)
,因为在删除元素的时候,这两种方法都需要通过循环来定位节点,删除元素;查询数据的时间复杂度还为O(n)
,因为都需要通过循环来定位;修改数据的时间复杂度也为O(n)
,原因同查询数据的时间复杂度的原因,最后只有获取链表大小的时间复杂度为O(1)
,因为这一些方法都通过我私有的成员变量来获取。
虽然来看,我不太行。但是能体现出我们链表优点的,最优是经过一些成长的双向循环链表,他能快速的往尾部插入数据,时间复杂度为O(1)
,删除尾部元素,时间复杂度也为O(1)
,是我们链表的骄傲!当我想到这个双向循环链表时,我不禁想到了以后的美好未来:在未来中,数据结构们的运行速度将会更快,内存开销将会更少,人类们的生活也将因为这些变得越来越便携,真是一个美好的未来啊!
下篇预告
粗心的连点器
相关文章:
链表的介绍
目录 引言优缺点与链表相似的数据结构注意事项单向链表的实现基础实现创建类创建成员变量创建特殊方法 增加数据push_back方法insert方法 删除数据del_back方法del_index方法 clear方法查询数据at方法与重载的中括号运算符toArray方法indexOf方法 修改数据获取链表大小测试方法…...
背着开发板回家过年~
大家好,我是bug菌~ 小明,过年了, 别再死磕什么STM32底层驱动、linux平台总线驱动框架、嵌入式实时操作系统源码这些了。 你背着电脑和开发板回家,压根没一点实际用处。 发小们潇洒地出入各种娱乐场所,唱着歌࿰…...
Kafka 日志存储 — 磁盘存储
Kafka 依赖与磁盘来存储和缓存消息,采用文件追加的方式来写入消息。顺序写盘的速度快于随机写内存。 1 磁盘存储 除顺序写入外,Kafka中大量使用了页缓存、零拷贝等技术来进一步提升吞吐性能。 1.1 页缓存 页缓存是操作系统实现的一种磁盘缓存&#x…...
【机器学习】自定义数据集 使用tensorflow框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
一、使用tensorflow框架实现逻辑回归 1. 数据部分: 首先自定义了一个简单的数据集,特征 X 是 100 个随机样本,每个样本一个特征,目标值 y 基于线性关系并添加了噪声。tensorflow框架不需要numpy 数组转换为相应的张量࿰…...
RK3568中使用QT opencv(显示基础图像)
文章目录 一、查看对应的开发环境是否有opencv的库二、QT使用opencv 一、查看对应的开发环境是否有opencv的库 在开发板中的/usr/lib目录下查看是否有opencv的库: 这里使用的是正点原子的ubuntu虚拟机,在他的虚拟机里面已经安装好了opencv的库。 二、…...
Brave132 编译指南 Windows 篇:获取源码(六)
1. 引言 在 Brave 浏览器 132 版本的编译过程中,获取源代码是至关重要的第一步。源代码包含了 Brave 浏览器的所有核心功能、特性和组件的实现细节,是深入理解、定制和优化 Brave 的基础。通过获取和管理源代码,开发者能够深入探索 Brave 的…...
解决 pip install 出现 error: subprocess-exited-with-error 错误的方法
解决 pip install 出现 error: subprocess-exited-with-error 错误的方法_pip安装报错 subprocess-CSDN博客文章浏览阅读10w次,点赞62次,收藏86次。通过上述步骤,我们成功解决了 pip install 时出现的 error: subprocess-exited-with-error 错…...
网络安全攻防实战:从基础防护到高级对抗
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 引言 在信息化时代,网络安全已经成为企业、政府和个人必须重视的问题。从数据泄露到勒索软件攻击,每一次…...
DeepSeek大模型技术解析:从架构到应用的全面探索
一、引言 在人工智能领域,大模型的发展日新月异,其中DeepSeek大模型凭借其卓越的性能和广泛的应用场景,迅速成为业界的焦点。本文旨在深入剖析DeepSeek大模型的技术细节,从架构到应用进行全面探索,以期为读者提供一个…...
Deepseek的api调用报错乱码问题
最近的deepseek也是很火,但是在调用api的过程中也会出现一些大大小小的问题,所以这里也给出一种问题和他的解决方案,报错的类型如下图所示 API Streaming Failed Command failed with exit code 1: powershell (Get-CimInstance -ClassName W…...
.NET Core 中依赖注入的使用
ASP.NET Core中服务注入的地方 在ASP.NET Core项目中一般不需要自己创建ServiceCollection、IServiceProvider。在Program.cs的builder.Build()之前向builder.Services中注入。在Controller中可以通过构造方法注入服务。 低使用频率的服务 把Action用到的服务通过Action的参…...
Mysql Resultset 解析记录
Mysql Resultset 解析记录 结果集消息头字段定义结果数据完整spicy文件 结果集消息头 消息头由消息体长度消息序列号消息体组成;消息头长度为3字节,消息序列号长度为1字节。 结果集的消息头消息体内容为结果集的列数。 结果集消息头的spicy1格式如下&a…...
ThinkPhp伪静态设置后,访问静态资源也提示找不到Controller
ThinkPhp没有配置伪静态时,除了默认的IndexController能访问,其他路由Controller都访问不到,提示404错误。配置了伪静态后就解决了这个问题。 但是当我的ThinkPhp后台项目中有静态资源放在public目录(或子目录)中需要…...
【回溯+剪枝】找出所有子集的异或总和再求和 全排列Ⅱ
文章目录 1863. 找出所有子集的异或总和再求和解题思路:子集问题解法(回溯 剪枝)47. 全排列 II解题思路:排序 回溯 剪枝 1863. 找出所有子集的异或总和再求和 1863. 找出所有子集的异或总和再求和 一个数组的 异或总和 定义为…...
单细胞-第五节 多样本数据分析,打分R包AUCell
文件在单细胞\5_GC_py\1_single_cell\3.AUCell.Rmd 1.基因 rm(list = ls()) load("g.Rdata")2.AUCell https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9897923 IF: NA NA NA用这个文章里的方法,将单细胞亚群的marker基因与ros相关基因取交集,用作AUCell的基因集…...
锁升级过程与优化操作
前文我们学习了CAS自旋锁知道CAS对应的就是一条指令操作,属于一种轻量级锁,那么有轻必有重,从无锁到轻量级锁到重量级锁是一个升级过程,此文我们对锁升级的过程以及一些优化锁的操作一探究竟。 1. 锁升级 从前文 《程序员不可能不…...
android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色
安卓自定义DatePicker选中日期颜色 背景:解决方案:方案一:方案二:实践效果: 背景: 最近在尝试用原生安卓实现仿element-ui表单校验功能,其中的的选择日期涉及到安卓DatePicker组件的使用&#…...
Kafka常见问题之 `javax.management.InstanceAlreadyExistsException`
文章目录 Kafka常见问题之 javax.management.InstanceAlreadyExistsException1. 概述2. 常见原因3. 具体异常示例4. 解决方案4.1 确保单一 Kafka Producer 实例4.2 配置 Kafka Broker 和 Producer 使用唯一的 JMX 名称(对于Producer重点检查 client.id)4…...
数据分析系列--③RapidMiner算子说明及数据预处理
一、算子说明 1.新建过程 2.算子状态灯 状态灯说明: (1)状态指示灯: 红色:指示灯说明有参数未被设置或输入端口未被连接等问题; 黄色:指示灯说明还未执行算子,不管配置是否基本齐全; 绿色:指示灯说明一切正常,已成功执行算子。 (2)三角…...
Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)
文章目录 Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理(Plugin Management)基础配置模板案例:Android项目标准配…...
专为课堂打造:宏碁推出三款全新耐用型 Chromebook
IT之家 1 月 25 日消息,宏碁(Acer)昨日(1 月 24 日)发布公告,针对教育市场,推出 Chromebook Spin 512 (R857T)、Chromebook Spin 511 (R757T) 和 Chromebook 511 (C737) 三款产品,兼…...
电商系统-用户认证(三)基于公钥解析JWT令牌
一、 基于私钥生成jwt令牌 步骤: 导入认证服务 将shangcheng_user_auth工程导入到项目中去,如下图 启动eureka,再启动认证服务 3) 认证服务中创建测试类 public class CreateJwtTest { /**** 创建令牌测试*/Testpublic voi…...
验证回文串
hello 大家好!今天开写一个新章节,每一天一道算法题。让我们一起来学习算法思维吧! function isPalindrome(s) {// 第一步:将字符串中的所有大写字符转换为小写字符s s.toLowerCase();// 第二步:使用正则表达式移除所…...
Java定时任务实现方案(四)——Spring Task
Spring Task 这篇笔记,我们要来介绍实现Java定时任务的第四个方案,使用Spring Task,以及该方案的优点和缺点。 Spring Task是Spring框架提供的一个轻量级任务调度框架,用于简化任务调度的开放,通过注解或XML配置的…...
Python 数据分析 - Matplotlib 绘图
Python 数据分析 - Matplotlib 绘图 简介绘图折线图单线多线子图 散点图直方图条形图纵置横置多条 饼图 简介 Matplotlib 是 Python 提供的一个绘图库,通过该库我们可以很容易的绘制出折线图、直方图、散点图、饼图等丰富的统计图,安装使用 pip install…...
深入探讨数据库索引类型:B-tree、Hash、GIN与GiST的对比与应用
title: 深入探讨数据库索引类型:B-tree、Hash、GIN与GiST的对比与应用 date: 2025/1/26 updated: 2025/1/26 author: cmdragon excerpt: 在现代数据库管理系统中,索引技术是提高查询性能的重要手段。当数据量不断增长时,如何快速、有效地访问这些数据成为了数据库设计的核…...
【Redis】hash 类型的介绍和常用命令
1. 介绍 Redis 中存储的 key-value 本身就是哈希表的结构,存储的 value 也可以是一个哈希表的结构 这里每一个 key 对应的一个 哈希类型用 field-value 来表示 2. 常用命令 命令 介绍 时间复杂度 hset key field value 用于设置哈希表 key 中字段 field 的值为…...
World Creator地形导入UE
修改导出分辨率1009x1009, 虚幻默认参数的整体分辨率是1009 导出预设选择高度图(heigh map)格式选择PNG 16位,或者RAW 16位,需要反转y轴(与虚幻不同),命名格式会自动带一个 , 将改成_ 或者删掉自己命名 &am…...
mybatis(104/134)
动态sql标签,用于选择查询 if标签 where标签 :自动生成where,取决于后面有没有条件,会自动去除条件前面的and和or,不会去除语句后面的 trim标签:自动生成where,在语句后自动去除后缀and和or for…...
制造企业的成本核算
一、生产成本与制造费用的区别 (1)生产成本,是直接用于产品生产,构成产品实体的材料成本。 包括企业在生产经营过程中实际消耗的原材料、辅助材料、备品备件、外购半成品、燃料、动力包装物以及其它直接材料,和直接参加产品生产的工人工资,以及按生产工人的工资总额和规…...
Windows中本地组策略编辑器gpedit.msc打不开/微软远程桌面无法复制粘贴
目录 背景 解决gpedit.msc打不开 解决复制粘贴 剪贴板的问题 启用远程桌面剪贴板与驱动器 重启RDP剪贴板监视程序 以上都不行?可能是操作被Win11系统阻止 最后 背景 远程桌面无法复制粘贴,需要查看下主机策略组设置,结果按WinR输入…...
详解排序算法
文章目录 1. 排序算法分类2. 比较排序算法介绍2.1 插入排序2.1.1 直接插入排序2.1.2 希尔排序 2.2 选择排序2.2.1 直接选择排序2.2.2 堆排序2.2.2.1 向下调整算法建堆2.2.2.2 向上调整算法建堆2.2.2.3 进行堆排序2.2.2.4 堆排序时间、空间复杂度分析2.2.2.5 利用堆排序解决TOP-…...
练习题 - Django 4.x File 文件上传使用示例和配置方法
在现代的 web 应用开发中,文件上传是一个常见的功能,无论是用户上传头像、上传文档,还是其他类型的文件,处理文件上传都是开发者必须掌握的技能之一。Django 作为一个流行的 Python web 框架,提供了便捷的文件上传功能和配置方法。学习如何在 Django 中实现文件上传,不仅…...
Vue 响应式渲染 - 待办事项简单实现
Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue 响应式渲染 - 待办事项简单实现 目录 待办事项简单实现 页面初始化 双向绑定的指令 增加留言列表设置 增加删除按钮 最后优化 总结 待办事项简单实现 页面初始化 对页面进行vue的引入、创建输入框和按钮及实例化V…...
【福州市AOI小区面】shp数据学校大厦商场等占地范围面数据内容测评
AOI城区小区面样图和数据范围查看: — 字段里面有name字段。分类比较多tpye:每个值代表一个类型。比如字段type中1549代表小区住宅,1563代表学校。小区、学校等占地面积范围数据 —— 小区范围占地面积面数据shp格式 无偏移坐标,只…...
llama.cpp LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK2
llama.cpp LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK2 1. LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK22. LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK23. struct ggml_cgraph * build_deepseek() and struct ggml_cgraph * build_deepseek2()References 不宜吹捧中国大语言模型的同…...
k8s简介,k8s环境搭建
目录 K8s简介环境搭建和准备工作修改主机名(所有节点)配置静态IP(所有节点)关闭防火墙和seLinux,清除iptables规则(所有节点)关闭交换分区(所有节点)修改/etc/hosts文件&…...
2024年个人总结
序 照例,每年都有的个人年度总结来了,看了很多其他大佬的总结,感觉自己的2024过于单薄,故事也不太丰满,自己就回去比较,自己哪里做的不好 ?但后来发现已经进入了一个思维误区。 年度总结年度总结…...
【落羽的落羽 数据结构篇】顺序表
文章目录 一、线性表二、顺序表1. 概念与分类2. 准备工作3. 静态顺序表4. 动态顺序表4.1 定义顺序表结构4.2 顺序表的初始化4.3 检查空间是否足够4.3 尾部插入数据4.4 头部插入数据4.5 尾部删除数据4.6 头部删除数据4.7 在指定位置插入数据4.8 在指定位置删除数据4.9 顺序表的销…...
麒麟操作系统服务架构保姆级教程(十四)iptables防火墙四表五链和防火墙应用案例
如果你想拥有你从未拥有过的东西,那么你必须去做你从未做过的事情 防火墙在运维工作中有着不可或缺的重要性。首先,它是保障网络安全的关键防线,通过设置访问控制规则,可精准过滤非法网络流量,有效阻挡外部黑客攻击、恶…...
Linux之详谈——权限管理
目录 小 峰 编 程 编辑 一、权限概述 1、什么是权限 2、为什么要设置权限 3、Linux中的权限类别- 4、Linux中文件所有者 1)所有者分类(谁) 2)所有者的表示方法 ① u(the user who owns it)(属主权限&…...
第05章 13 椭球体张量可视化应用一则-神经束追踪
在神经束追踪(Tractography)中,椭球体张量(Ellipsoid Tensor)通常用于描述神经纤维的方向和扩散特性。这种技术广泛应用于磁共振成像(MRI)的扩散张量成像(DTI)数据中。VT…...
Celery
https://www.bilibili.com/video/BV1RGDEY5ERB 架构 简单任务 执行 包结构 本示例: app 添加任务 获取结果 配置延时任务 任务配置 beat 提交定时任务...
JavaScript系列(48)-- 3D渲染引擎实现详解
JavaScript 3D渲染引擎实现详解 🎮 今天,让我们深入探讨JavaScript的3D渲染引擎实现。通过WebGL和现代JavaScript技术,我们可以构建一个功能完整的3D渲染系统。 3D渲染基础概念 🌟 💡 小知识:3D渲染引擎的…...
Golang并发机制及CSP并发模型
Golang 并发机制及 CSP 并发模型 Golang 是一门为并发而生的语言,其并发机制基于 CSP(Communicating Sequential Processes,通信顺序过程) 模型。CSP 是一种描述并发系统中交互模式的正式语言,强调通过通信来共享内存…...
使用 Docker + Nginx + Certbot 实现自动化管理 SSL 证书
使用 Docker Nginx Certbot 实现自动化管理 SSL 证书 在互联网安全环境日益重要的今天,为站点或应用部署 HTTPS 已经成为一种常态。然而,手动申请并续期证书既繁琐又容易出错。本文将以 Nginx Certbot 为示例,基于 Docker 容器来搭建一个…...
游戏策划的分类
P3游戏策划分类 1.程序2.美术3.策划 程序:一般分为客户端程序和服务器程序 客户端程序一般负责游戏的前端画面表现 服务器程序负责游戏的后端运算 美术:角色原画,角色模型动作,场景原画,场景模型,UI设计&a…...
Edge-TTS在广电系统中的语音合成技术的创新应用
Edge-TTS在广电系统中的语音合成技术的创新应用 作者:本人是一名县级融媒体中心的工程师,多年来一直坚持学习、提升自己。喜欢Python编程、人工智能、网络安全等多领域的技术。 摘要 随着人工智能技术的快速发展,文字转语音(Te…...
python学opencv|读取图像(四十七)使用cv2.bitwise_not()函数实现图像按位取反运算
【0】基础定义 按位与运算:两个等长度二进制数上下对齐,全1取1,其余取0。按位或运算:两个等长度二进制数上下对齐,有1取1,其余取0。 按位取反运算:一个二进制数,0变1,1变0。 【1】…...
一文讲解Java中Object类常用的方法
在Java中,经常提到一个词“万物皆对象”,其中的“万物”指的是Java中的所有类,而这些类都是Object类的子类; Object主要提供了11个方法,大致可以分为六类: 对象比较: public native int has…...