02线性表 - 链表

news2024/9/22 13:42:01

这里是只讲干货不讲废话的炽念,这个系列的文章是为了我自己以后复习数据结构而写,所以可能会用一种我自己能够听懂的方式来描述,不会像书本上那么枯燥和无聊,且全系列的代码均是可运行的代码,关键地方会给出注释^_^

全文1W+字

版本:C++17

编译器:Clion 2023.3.24

暂时只给出代码,不会涉及到基础知识的讲解

 1.链表的定义

1.1定义链表结点

// 链表的核心是定义结点
typedef struct list_node{ // C语言中必须要先声明 list_node,不然编译器会报错,C++可以忽略这个问题
    Element value;                // 结点存储的数据元素
    struct list_node *next;       // 指向下一个结点的指针
}ListNode;

1.2定义链表头结点

// 链表的表头
typedef struct {
    ListNode head;        // 头结点,通常不存储实际数据,用作链表的起始点
    int len;              // 链表的长度,用于记录链表中实际结点的数量
}LinkList;

2.链表的实现函数

2.1.表的创建以及删除

// 创建链表和删除链表
LinkList *createLinkList();                   // 创建一个链表

void releaseLinkList(LinkList* linkList);     // 释放一个链表

 

2.2.向表中插入元素

// 三种插入方式
int insertLinkList(LinkList *linkList, int pos, Element val);   // 任意位置上插入

int headInsertLinkList(LinkList *linkList, Element val);        // 头插法

int tailInsertLinkList(LinkList *linkList, Element val);        // 尾插法

 

2.3.表的展示

void showLinkList(LinkList *linkList);                      // 显示链表内的元素

 

2.4.删除表中的元素

int deleteLinkList(LinkList *linkList, Element val);        // 删除链表中的特定元素

 

2.5逆转链表

void reverseLinklist(LinkList *linkList);                   // 逆转链表

 

 

 

 

3.实现函数的代码

3.1 createLinkList函数的实现

函数定义:
LinkList *createLinkList();

 

函数功能:
该函数用于创建一个空的链表,并返回链表的头结点指针

 

实现思路:
a.申请一个类型为LinkList,大小为sizeof(LinkList)的头结点

b.判空,判断申请是否成功

c.初始化LinkList->len = 0, LinkList->head.value = 0(根据实际情况来定义这个值)

d.初始化LinkList->head.next = NULL

e.返回指向新创建链表头结点的指针

 

具体实现代码:
LinkList *createLinkList() {
    LinkList *linkList = (LinkList *) malloc(sizeof (LinkList));
    if (!linkList){
        printf("Malloc linklist failed\n");
        return NULL;
    }

    linkList->len = 0;              // 表示链表的长度
    linkList->head.value = 0;       // 根据具体的场景来定义这个值
    linkList->head.next = NULL;

    printf("Create linklist success!\n");
    return linkList;
}

 

测试代码:
int main(){
    LinkList *linkList= createLinkList();
    return 0;
}

 

测试结果: 

 

 

3.2 releaseLinkList函数的实现

函数定义:
void releaseLinkList(LinkList* linkList);
函数功能:
释放链表中的所有节点(包括头节点),避免内存泄漏
实现思路:

方法一:头删法

a.初始化:
获取链表头结点地址并赋值给 node 指针。
node->next 指向待删除结点的下一个结点,用于备份


b.循环删除:
循环遍历链表,条件为 node->next 不为空。
使用 tmp 指针指向要删除的结点 (node->next)。
将 node 的 next 指针指向 tmp 的下一个结点 (tmp->next),移除 tmp 指向的结点。
释放 tmp 指向的结点内存。
更新链表长度,减去 1


c.释放头结点:
循环结束后,释放头结点的内存

方法二:循环删除法

a.初始化: 
将 node 指针指向链表的头结点的下一个结点,准备开始遍历链表


b.循环删除:
使用 while 循环遍历链表,直到到达链表末尾。在循环中:
备份当前要删除的结点到 tmp 指针
将当前结点的 next 指针指向下一个结点,从而将 tmp 指向的结点从链表中移除
释放 tmp 指向的结点的内存
更新链表长度,减去 1


c.释放头结点: 
最后释放头结点的内存
具体实现代码:
方法一:头删法(不断删除头结点后的那个结点,直到为空)
void releaseLinkList1(LinkList *linkList) {
    if (linkList){
        ListNode *node = &linkList->head;
        // 不断的删除头结点的下一个指向,直到为空(头删法)
        while (node->next){
            ListNode *tmp = node->next; // 备份要删除的结点
            node->next = tmp->next;     // 这里为什么不是node = node->next;
            free(tmp);                  // 因为这样已经移动了头结点,会失去对前一个节点的引用,可能导致内存泄露
            linkList->len--;
        }

       
        printf("Release success! LinkList have %d node\n",linkList->len);
        free(linkList);
    }
}

 

 

方法二:循环删除法
void releaseLinkList2(LinkList *linkList){
    if (linkList) {
        ListNode *node = linkList->head.next;

        // 使用循环遍历链表,释放除头结点外的每个节点(循环删除法)
        while (node) {
            ListNode *tmp = node;           // 备份当前节点
            node = node->next;              // 移动到下一个节点
            free(tmp);                      // 释放当前节点
            linkList->len--;
        }

        printf("Release success! LinkList have %d node\n",linkList->len);
        free(linkList);
    }
}

 

 

测试代码:

因为需要知道链表中还剩下多少元素,所以先引入加入函数

1.头删法测试代码:
int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    insertLinkList(linkList, 2, 888);
    showLinkList(linkList);

    insertLinkList(linkList, 1, 888);
    showLinkList(linkList);

    tailInsertLinkList(linkList, 999);
    showLinkList(linkList);

    tailInsertLinkList(linkList, 111);
    showLinkList(linkList);

    releaseLinkList1(linkList);


    return 0;
}

 

2.循环删除法测试代码:
int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    insertLinkList(linkList, 2, 888);
    showLinkList(linkList);

    insertLinkList(linkList, 1, 888);
    showLinkList(linkList);

    tailInsertLinkList(linkList, 999);
    showLinkList(linkList);

    tailInsertLinkList(linkList, 111);
    showLinkList(linkList);

    releaseLinkList2(linkList);


    return 0;
}

 

测试结果:
1.头删法测试结果:

2.循环删除法测试结果:

 

 

 3.3 insertLinkList && headInsertLinkList && tailInsertLinkList 函数的实现

函数定义:
int insertLinkList(LinkList *linkList, int pos, Element val);   // 任意位置上插入

int headInsertLinkList(LinkList *linkList, Element val);        // 头插法

int tailInsertLinkList(LinkList *linkList, Element val);        // 尾插法
函数功能:

1.insertLinkList

在链表的指定位置插入新节点

 

 2.headInsertLinkList

在链表头部插入新节点

 

 3.tailInsertLinkList

 在链表尾部插入新节点
实现思路:

1.insertLinkList

a.判断链表是否为空,判断插入位置是否合法
 * 在 pos 的位置上插入,就要找到 pos-1 的位置
 * pos = 1 逻辑位置上的插入,就定义 cnt = 0 是头节点的位置
 * pos = 0 逻辑位置上的插入,就定义 cnt = -1 是头节点的位置

b.通过遍历找到待插入结点的前一个结点

c.判断 node 是否为空(逻辑完备性)

d.申请结点,将新节点 newNode->next 设为 NULL,将新节点的 value 设为 val

e.将 newNode->next 赋值为 node->next    //这两步一定要注意顺序

f.将 node->next 赋值为 newNode          //这两步一定要注意顺序

g.更新链表长度,LinkList->len++

2.headInsertLinkList

a.判断链表是否为空

b.申请结点,将新节点 newNode->next 设为 NULL,将新节点的 value 设为 val

c.将 newNode->next 赋值为 LinkList->head.next    //这两步一定要注意顺序

d.将 LinkList->head.next 赋值为 newNode->next    //这两步一定要注意顺序

e.更新链表长度,LinkList->len++

3.tailInsertLinkList

a.判断链表是否为空

b.申请结点,将新节点 newNode->next 设为 NULL,将新节点的 value 设为 val

c.判断 LinkList 是否为只有头节点的链表

d.如果是只有头节点的链表,则直接插入到头节点后
    *即 LinkList->head.next = newNode;

e.如果不是,则不断循环找到尾节点,之后插入到尾节点后
    *即 node->next = newNode;

g.更新链表长度,LinkList->len++

 

 

具体实现代码:

1.insertLinkList

int insertLinkList(LinkList *linkList, int pos, Element val) {
    if (!linkList){
        printf("LinkList is null. Insert error!\n");
        return -1;
    }

    if (pos < 1 || pos > linkList->len + 1){
        printf("Insert position out of range!\n");
        return -1;
    }

    ListNode *node = &linkList->head;
    int cnt = 0;

    while (node && cnt < pos - 1){      // 找到待插入位置的前一个位置
        node = node->next;
        cnt++;
    }

    // 判断是找到了pos-1的位置,还是遍历完链表都没有找到
    if (node == NULL){                  // 为了逻辑完备性,多加一段代码
        printf("Insert position out of range!\n");
        return -1;
    }

    ListNode *newNode = (ListNode *) malloc(sizeof (ListNode)); //这段是核心代码
    newNode->next =  NULL;
    newNode->value = val;

    newNode->next = node->next;         // 这里注意顺序,一定要先保存当前结点的下一个结点的位置
    node->next = newNode;

    linkList->len++;
    return 0;
}

2.headInsertLinkList

int headInsertLinkList(LinkList *linkList, Element val) {
    if (!linkList){
        printf("LinkList is null. Insert error!\n");
        return -1;
    }

    ListNode *newNode = (ListNode *) malloc(sizeof (ListNode));
    if (newNode == NULL) {
        printf("Memory allocation failed.\n");
        return -1;
    }
    newNode->next = NULL;
    newNode->value = val;

    newNode->next = linkList->head.next;
    linkList->head.next = newNode;
    linkList->len++;

    return 0;
}

 

3.tailInsertLinkList

int tailInsertLinkList(LinkList *linkList, Element val) {
    if (!linkList) {
        printf("LinkList is null. Insert error!\n");
        return -1;
    }

    ListNode *newNode = (ListNode *) malloc(sizeof(ListNode));
    if (newNode == NULL) {
        printf("Memory allocation failed.\n");
        return -1;
    }
    newNode->value = val;
    newNode->next = NULL; // 初始化新节点的 next 指针为空

    if (linkList->head.next == NULL) { // 链表为空,直接将新节点插入到头节点
        linkList->head.next = newNode;
    } else {
        ListNode *node = linkList->head.next;
        while (node->next != NULL) { // 找到最后一个节点
            node = node->next;
        }
        node->next = newNode; // 将最后一个节点的 next 指向新节点
    }

    linkList->len++;
    return 0;
}

测试代码:

1.insertLinkList

int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    insertLinkList(linkList, 5, 888);
    showLinkList(linkList);

    insertLinkList(linkList, 2, 888);
    showLinkList(linkList);

    insertLinkList(linkList, 1, 888);
    showLinkList(linkList);

    insertLinkList(linkList,999, 888);
    showLinkList(linkList);

    releaseLinkList2(linkList);


    return 0;
}

 2.headInsertLinkList 

int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);
    
    releaseLinkList2(linkList);
    
    return 0;
}

 3.tailInsertLinkList

int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        tailInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    releaseLinkList2(linkList);

    return 0;
}

 

 

测试结果:

1.insertLinkList

 2.headInsertLinkList 

 3.tailInsertLinkList

3.4 void showLinkList(LinkList *linkList);

函数定义:
void showLinkList(LinkList *linkList);              // 显示链表内的元素

 

函数功能:
将链表中的所有元素依次打印到控制台
实现思路:
a.判断传入链表是否为空

b.定义 node 为头节点后的第一个节点

c.遍历链表,同时打印node->val,直到链表为空
具体实现代码:
void showLinkList(LinkList *linkList) {
    if (!linkList){
        printf("LinkList is null. Show error!\n");
        return;
    }

    ListNode *node = linkList->head.next;
    while (node){
        printf("%d ", node->value);
        node = node->next;
    }
    printf("\n");
}

 

测试代码:
int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    releaseLinkList2(linkList);
    return 0;
}

 

测试结果:
 

3.5 deleteLinkList函数的实现

函数定义:
int deleteLinkList(LinkList *linkList, Element val)
函数功能:
从链表中删除第一个值为 val 的节点
实现思路:
a.判断传入的链表是否为空

b.用循环找到待删除节点的 前一个 结点

c.判断链表的下一个结点是否为空(逻辑完备性)

d.用一个指针 tmp 指向待删除的结点

e.将 node->next(待删除结点的前一个结点) 设为 tmp->next(删除结点的下一个结点)

f.释放掉 tmp 的空间

g.更新链表长度,LinkList->len--
具体实现代码:
int deleteLinkList(LinkList *linkList, Element val) {
    if (!linkList) {
        printf("LinkList is null. Delete error!\n");
        return -1;
    }

    ListNode *node = &linkList->head;
    while (node->next && node->next->value != val){
        node = node->next;
    }

    if (!node->next){
        printf("Find element failed! Delete failed!\n");
        return -1;
    }

    ListNode *tmp = node->next;        // 注意顺序
    node->next = tmp->next;
    free(tmp);
    linkList->len--;
    return 0;
}
测试代码:
int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    deleteLinkList(linkList, 104);
    showLinkList(linkList);

    deleteLinkList(linkList, 100);
    showLinkList(linkList);

    deleteLinkList(linkList, 104);
    showLinkList(linkList);

    deleteLinkList(linkList, 102);
    showLinkList(linkList);
    releaseLinkList2(linkList);
    return 0;
}
测试结果:

3.6 reverseLinklist函数的实现

函数定义:
void reverseLinklist(LinkList *linkList);
函数功能:
将给定的单链表反转
实现思路:

方法一:

a.判断当前链表是否为空

b.初始化 
cur = LinkList->head.next            (头节点的下一个)
pre = NULL
LinkList->head.next = NULL           (注意cur一定要在之前就要赋值)

c.循环
备份当前结点                          (pre = cur)
移动cur避免丢失                       (cur = cur->next)
将pre->next = LinkList->head.next    (不断往头节点后插入结点)
将 LinkList->head.next = pre         (将头节点指向正确的位置)

方法二:

a.判断当前链表是否为空

b.初始化 
cur = LinkList->head.next             (头节点的下一个)
nxt = NULL
LinkList->head.next = NULL            (注意cur一定要在之前就要赋值)

c.循环
备份下一个结点                         (nxt = cur->next)
将 cur->next = LinkList->head.next    (不断往头节点后插入结点)
将 LinkList->head.next = cur          (将头节点指向正确的位置)
cur = nxt                             (避免结点丢失)

方法三:

a. 将链表所有的结点全部压入到栈中(除了头节点)
b. 利用栈先进后出的特性,出栈一个元素,头节点就连接一个元素
c. 注意使用 尾插法 来连接元素

具体实现代码:

方法一(备份当前节点,反转当前结点):

void reverseLinklist1(LinkList *linkList) {
    if (!linkList) {
        printf("LinkList is null. Delete error!\n");
        return;
    }

    ListNode *cur = linkList->head.next;
    ListNode *pre = NULL;
    linkList->head.next = NULL;

    while(cur){
        pre = cur;
        cur = cur->next;
        pre->next = linkList->head.next;
        linkList->head.next = pre;
    }

    printf("Reverse success!\n");
}

 

方法二(备份下一个结点,反转当前结点):

void reverseLinklist2(LinkList *linkList) {
    if (!linkList) {
        printf("LinkList is null. Delete error!\n");
        return;
    }

    ListNode *cur = linkList->head.next;
    ListNode *nxt = NULL;
    linkList->head.next = NULL;

    while (cur){
        nxt = cur->next;
        cur->next = linkList->head.next;
        linkList->head.next = cur;
        cur = nxt;
    }

    printf("Reverse success!\n");
}

方法三:

这里在栈的部分写,到时候放一个链接

测试代码:

方法一:

int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    reverseLinklist1(linkList);
    
    releaseLinkList2(linkList);
    return 0;
}

方法二:

int main(){
    LinkList *linkList= createLinkList();
    for (int i = 0; i < 5; i++){
        headInsertLinkList(linkList, i+100);
    }
    showLinkList(linkList);

    reverseLinklist2(linkList);

    releaseLinkList2(linkList);
    return 0;
}

测试结果:

方法一:


 

方法二:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows edge自带的pdf分割工具(功能)

WPS分割pdf得会员&#xff0c;要充值&#xff01;网上一顿乱找&#xff0c;发现最简单&#xff0c;最好用&#xff0c;免费的还是回到Windows。 Windows上直接在edge浏览器打开PDF&#xff0c;点击 打印 按钮,页面下选择对应页数 打印机 选择 另存为PDF&#xff0c;然后保存就…

memcached 高性能内存对象缓存

memcached 高性能内存对象缓存 memcache是一款开源的高性能分布式内存对象缓存系统&#xff0c;常用于做大型动态web服务器的中间件缓存。 mamcached做web服务的中间缓存示意图 当web服务器接收到请求需要处理动态页面元素时&#xff0c;通常要去数据库调用数据&#xff0c;但…

ProtoBuf的安装(win+ubuntu+centos版本)

Win下安装ProtoBuf教程 WProtoBuf Win版本 上方链接就是ProtoBuf官方在Github上面的仓库&#xff0c;我这里下的是21.11版本&#xff0c;至于你要下哪个版本&#xff0c;可以根据自己的需要去下载。 首先点击链接&#xff0c;进入首页&#xff0c;向下滑就可以找到ProtoBuf…

加密传输及相关安全验证:

1.1. 加密&#xff1a; 1.1.1. 对称加密&#xff1a; 特点&#xff1a;加解密用一个密钥&#xff0c;加解密效率高&#xff0c;速度快&#xff0c;有密钥交互的问题问题&#xff1a;双方如何交互对称密钥的问题&#xff0c;用非对称密钥的公钥加密对称密钥的混合加密方式常用…

IP溯源工具--IPTraceabilityTool

工具地址&#xff1a;xingyunsec/IPTraceabilityTool: 蓝队值守利器-IP溯源工具 (github.com) 工具介绍&#xff1a; 在攻防演练期间&#xff0c;对于值守人员&#xff0c;某些客户要求对攻击IP都进行分析溯源&#xff0c;发现攻击IP的时候&#xff0c;需要针对攻击IP进行分析…

PHP手边酒店多商户版平台小程序系统源码

&#x1f3e8;【旅行新宠】手边酒店多商户版小程序&#xff0c;一键解锁住宿新体验&#xff01;&#x1f6cc; &#x1f308;【开篇&#xff1a;旅行新伴侣&#xff0c;尽在掌握】&#x1f308; 还在为旅行中的住宿选择而纠结吗&#xff1f;是时候告别繁琐的搜索和比价过程&a…

js继承之构造函数继承

最近在看js红宝书&#xff0c;学到了继承这一章节&#xff0c;看到了下图这段代码根据自己理解不明白为什么两次实例的colors值不一样 又是自己画图又是查找资料看别人如何理解的&#xff0c;今天才按自己的理解搞明白为啥。可能我的理解也是有偏差错误的&#xff0c;希望佬可以…

开源防病毒工具--ClamAV

产品文档&#xff1a;简介 - ClamAV 文档 开源地址&#xff1a;Cisco-Talos/clamav&#xff1a;ClamAV - 文档在这里&#xff1a;https://docs.clamav.net (github.com) 一、引言 ClamAV&#xff08;Clam AntiVirus&#xff09;是一个开源的防病毒工具&#xff0c;广泛应用…

【Node.js】会话控制

express 中操作 cookie cookie 是保存在浏览器端的一小块数据。 cookie 是按照域名划分保存的。 浏览器向服务器发送请求时&#xff0c;会自动将 当前域名下可用的 cookie 设置在请求头中&#xff0c;然后传递给服务器。 这个请求头的名字也叫 cookie &#xff0c;所以将 c…

NVidia 的 gpu 开源 Linux Kernel Module Driver 编译 安装 使用

见面礼&#xff0c;动态查看gpu使用情况&#xff0c;每隔2秒钟自动执行一次 nvidia-smi $ watch -n 2 nvidia-smi 1&#xff0c;找一台nv kmd列表中支持的 GPU 的电脑&#xff0c;安装ubuntu22.04 列表见 github of the kmd source code。 因为 cuda sdk 12.3支持最高到 ubu…

AMEYA360:思瑞浦推出汽车级理想二极管ORing控制器TPS65R01Q

聚焦高性能模拟芯片和嵌入式处理器的半导体供应商思瑞浦3PEAK(股票代码&#xff1a;688536)发布汽车级理想二极管ORing控制器TPS65R01Q。 TPS65R01Q拥有20mV正向调节功能&#xff0c;降低系统损耗。快速反向关断(Typ&#xff1a;0.39μs)&#xff0c;在电池反向和各种汽车电气瞬…

OCR拍照识别采购单视频介绍

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

【BUG】已解决:NOAUTH Authentication required

已解决&#xff1a;NOAUTH Authentication required 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区主理人…

Atlas架构与原理

作者&#xff1a;楼高 一、总体架构 Atlas 是一个可伸缩且功能丰富的数据管理系统&#xff0c;深度集成了 Hadoop 大数据组件。简单理解就是一个 跟 Hadoop 关系紧密的&#xff0c;可以用来做元数据管理的一个系统,整个结构图如下所示&#xff1a; Atlas可以分为以下几层&…

IAR嵌入式开发解决方案已全面支持芯科集成CX3288系列车规RISC-V MCU,共同推动汽车高品质应用的安全开发

中国上海&#xff0c;2024年7月16日 — 全球领先的嵌入式系统开发软件解决方案供应商IAR与芯科集成电路&#xff08;以下简称“芯科集成”&#xff09;联合宣布&#xff0c;最新版本IAR Embedded Workbench for RISC-V 3.30.2功能安全版已全面支持芯科集成CX3288系列车规RISC-V…

【Node.js】初识 Node.js

Node.js 概念 Node.js 是一个开源与跨平台的 JavaScript运行时环境 &#xff0c;在浏览器外运行 V8 JavaScript 引擎(Google Chrome的内核)&#xff0c;利用事件驱动、非阻塞和异步输入输出 等技术提高性能。 可以理解为 Node.js就是一个服务器端的、非阻塞式 l/O 的、事件驱…

《Windows API每日一练》10.3 公用对话框

Windows最初发行时的主要目标之一就是提倡一种标准化的用户界面。对于公用菜单 项来说&#xff0c;这一目标实现得很快。几乎所有的软件制造商都采用了Alt-File-Open组合来打开 文件。但是&#xff0c;真正用来打开文件的对话框却经常很不一样。 从Windows 3.1开始&#xff0c…

排序系列 之 选择排序

&#xff01;&#xff01;&#xff01;排序仅针对于数组哦本次排序是按照升序来的哦 介绍 快速排序英文名为SelectSort从数组中找到最小的放到前边 基本思路 1、默认待排序数组中第一个作为最小值2、找待排序数组&#xff08;注意不是整个数组哦&#xff09;中真正的最小值3…

使用LVS+NGinx+Netty实现数据接入

数据接入 链接参考文档 LVSKeepalived项目 车辆数据上收&#xff0c;TBox通过TCP协议连接到TSP平台 建立连接后进行数据上传。也可借由该连接实现远程控制等操作。 通过搭建 LV—NGinx—Netty实现高并发数据接入 LVS&#xff1a;四层负载均衡&#xff08;位于内核层&#x…

Django定时任务框架django-apscheduler的使用

1.安装库 pip install django-apscheduler 2.添加 install_app django_apscheduler 3.在app下添加一个task.py文件&#xff0c;用来实现具体的定时任务 task.pydef my_scheduled_job():print("这个任务每3秒执行一次", time.time()) 4.在app下创建一个manag…