【数据结构】【王道】【线性表】单链表的实现及基本操作(带头结点)(可直接运行)

2023-11-08

总目录


各部分的解释已经以注释形式写于代码中。

1.基本操作

1.1 结构体定义

// 带头结点
typedef struct LNode {  // 定义单链表结点类型
    int data;   // 数据域
    struct LNode *next; // 指针域
} LNode, *LinkList;

1.2 初始化

// 初始化一个单链表
bool InitList(LinkList &L) {
    L = (LNode *)malloc(sizeof(LNode)); // 分配一个结点的空间,当作头结点
    // 内存分配失败得到情况
    if(L == NULL) {
        return false;
    }
    // 将头结点指针域设为NULL,表示头结点之后暂时还没有结点
    L->next = NULL;
    return true;
}

1.3 判空

// 判断单链表是否为空
bool Empty(LinkList L) {
    // 有头结点,那么头结点指针域指向NULL,单链表即为空
    if(L->next == NULL) {
        return true;
    } else {
        return false;
    }
}

1.4 按位序插入

// 在第i个位置插入元素e
bool ListInsert(LinkList &L, int i, int e) {
    // 判断插入位序是否存在问题
    if(i < 1)
        return false;
    LNode *p;   // 指针p指向当前扫描到的结点
    int j = 0;  // 当前p指向的是第几个结点
    p = L;      // 初始令p指向头结点
    // 通过循环,找到第i-1个结点
    // 如果i大于链表长度,则不可插入,此时p指向最后结点的指针域,即NULL
    while(p != NULL && j < i - 1) {
        p = p->next;
        j++;
    }
    // p值为NULL说明遍历完成后仍未为找到位序为i的结点,说明i大于链表长度,i不合法
    if (p == NULL) {
        return false;
    }
    // 在第i-1个结点后插入新结点
    LNode *s = (LNode *)malloc(sizeof(LNode));
    // 注意顺序,应该先让要插入结点的指针域指向后一结点
    // 之后再断开前一结点与后一结点的指针,使前一结点指向要插入结点
    s->data = e; 
    s->next = p->next;
    //将结点s连到p后
    p->next = s;
    return true;
}

1.5 指定结点后插操作

// 指定结点后插操作:在p结点之后插入元素e
// LNode强调为结点
bool InsertNextNode(LNode *p, int e) {
    // p不合理的情况
    if(p == NULL) {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    // 内存分配失败的情况
    if(s == NULL) {
        return false;
    }
    // 此处先将要插入结点的指针域指向前一个结点的指针域,即后一个结点的地址
    // 之后再令前一个结点的指针域指向要插入结点
    // 顺序不可颠倒,否则可能出现找不到之后结点的情况
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

1.6 指定结点前插操作

// 指定结点前插操作:在p结点之前
// 此处可以通过一种特殊方法完成前插
// 本质上还是后插操作
bool InsertPriorNode(LNode *p, int e) {
    // p不合理的情况
    if(p == NULL) {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    // 内存分配失败的情况
    if(s == NULL) {
        return false;
    }
    // 插入操作
    // 通过将s插入p结点之后,然后将s结点与p结点的数据域进行互换
    // 可以视作完成了前插操作
    s->next = p->next;
    p->next = s;
    s->data = p->data;
    p->data =e;
    return true;
}

1.7 按位序删除

// 按位序删除
bool ListDelete(LinkList &L, int i, int &e) {
    // i不合理的情况
    if(i < 1) {
        return false;
    }
    LNode *p;   // 指针p指向当前扫描到的结点
    int j = 0;  // 当前p指向的是第几个结点
    // 初始令p指向头结点,即第0个结点
    p = L;
    // 通过遍历找到第i - 1个结点,即要删除结点的前驱结点
    while(p != NULL && j < i - 1) {
        p = p->next;
        j++;
    }
    // 若p等于NULL,则要么此链表为空,要么i值大于链表长度,显然不合理
    if(p == NULL) {
        return false;
    }
    // p->next为空表示第i-1个结点之后已经没有其他结点了,无法进行删除操作
    if(p->next == NULL) {
        return false;
    }
    // 删除操作
    // 就是将前驱结点指针域指向后继结点
    LNode *q = p->next;    
    e = q->data;
    p->next = q->next;
    // 不要忘记释放空间!!!
    free(q); 
    return true;
}

1.8 按位查找

// 按位查找,返回第i个元素
// 之前操作部分按位查找部分可以以此部分代码代替,提高代码复用性(封装)
LNode* GetElem(LinkList L, int i) {
    // 判断插入位序是否存在问题
    // 由于此是带头结点的情况,而头结点可以视作是第0个结点
    // 所以与之前遍历情况不同
    if(i < 0)
        return NULL;
    LNode *p;   // 指针p指向当前扫描到的结点
    int j = 0;  // 当前p指向的是第几个结点
    p = L;      // 初始令p指向头结点
    // 通过循环,找到第i个结点
    // 如果i大于链表长度,则找不到此节点,此时p指向最后结点的指针域,即NULL
    // 如果i初始为0,会直接返回头结点地址
    while(p != NULL && j < i) {
        p = p->next;
        j++;
    }
    return p;
}

1.9 按值查找

// 按值查找,找到数据域等于e的结点
LNode* LocateElem(LinkList L, int e) {
    LNode* p = L->next;
    // 从第一个结点开始查找数据域为e的结点
    // 找不到,则会在遍历后指向NULL
    while (p != NULL && p->data != e) {
        p = p->next;
    }
    return p;
}

1.10 表的长度

// 求表的长度
// 就是通过遍历所有结点,然后通过计数器来累加得到长度
int Length(LinkList L) {
    int len = 0;
    LNode* p = L;
    while(p->next != NULL) {
        p = p->next;
        len++;
    }
    return len;
}

1.11 单链表建立(尾插法)

// 尾插法
// 通过尾插法建立的链表,顺序为插入时元素的顺序
LinkList TailInsert(LinkList &L) {
    // 设置ElemType为整型
    int x;
    // 建立头结点(申请的空间为一个结点大小的空间)
    L = (LinkList)malloc(sizeof(LNode));
    // 初始化为空链表
    // 由于L在分配空间后,头指针可能并非指向NULL,而是其他任意区域,这可能导致问题发生
    // 动态分配的空间之前可能存在脏数据
    L->next = NULL;
    // 定义表尾指针
    // 对于尾插法,如果只通过头结点遍历的话
    // 每次插入时都要先遍历到表尾,时间复杂度为O(1+2+...+n-1)=O(n^2)
    // 所以选择增加一个尾指针,来避免遍历
    // s为要插入的结点,r为表尾指针
    LNode *s, *r = L;
    // 输入结点的值
    scanf("%d", &x);
    // 表示键入9999后建表结束
    while(x != 9999) {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        // r指向新的表尾结点
        r = s;
        // 继续输入下一个结点的值,直至输入9999结束
        scanf("%d", &x);
    }
    // 尾指针置空
    r->next = NULL;
    return L;
}

1.12 单链表建立(头插法)

// 头插法
// 通过头插法建立的链表,顺序为插入时元素的逆序
LinkList HeadInsert(LinkList &L) {
    // 设置ElemType为整型
    int x;
    // 建立头结点(申请的空间为一个结点大小的空间)
    L = (LinkList)malloc(sizeof(LNode));
    // 初始化为空链表
    // 由于L在分配空间后,头指针可能并非指向NULL,而是其他任意区域,这可能导致问题发生
    // 动态分配的空间之前可能存在脏数据
    L->next = NULL;
    // 不同于尾插法,头插法无需定义更多指针
    LNode* s;
    // 输入结点的值
    scanf("%d", &x);
    // 表示键入9999后建表结束
    while(x != 9999) {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        // 继续输入下一个结点的值,直至输入9999结束
        scanf("%d", &x);
    }
}

1.13 输出所有链表元素

// 输出所有链表元素
void PrintList(LinkList L) {
    if(Empty(L)) {
        printf("the list is empty");
    }
    LNode* p = L;
    while(p !=  NULL) {
        printf("%d  ", p->data);
        p = p->next;
    }
}

2.完整代码

#include<stdio.h>
#include<stdlib.h>

// 带头结点
typedef struct LNode {  // 定义单链表结点类型
    int data;   // 数据域
    struct LNode *next; // 指针域
} LNode, *LinkList;

// 初始化一个单链表
bool InitList(LinkList &L) {
    L = (LNode *)malloc(sizeof(LNode)); // 分配一个结点的空间,当作头结点
    // 内存分配失败得到情况
    if(L == NULL) {
        return false;
    }
    // 将头结点指针域设为NULL,表示头结点之后暂时还没有结点
    L->next = NULL;
    return true;
}

// 判断单链表是否为空
bool Empty(LinkList L) {
    // 有头结点,那么头结点指针域指向NULL,单链表即为空
    if(L->next == NULL) {
        return true;
    } else {
        return false;
    }
}

// 在第i个位置插入元素e
bool ListInsert(LinkList &L, int i, int e) {
    // 判断插入位序是否存在问题
    if(i < 1)
        return false;
    LNode *p;   // 指针p指向当前扫描到的结点
    int j = 0;  // 当前p指向的是第几个结点
    p = L;      // 初始令p指向头结点
    // 通过循环,找到第i-1个结点
    // 如果i大于链表长度,则不可插入,此时p指向最后结点的指针域,即NULL
    while(p != NULL && j < i - 1) {
        p = p->next;
        j++;
    }
    // p值为NULL说明遍历完成后仍未为找到位序为i的结点,说明i大于链表长度,i不合法
    if (p == NULL) {
        return false;
    }
    // 在第i-1个结点后插入新结点
    LNode *s = (LNode *)malloc(sizeof(LNode));
    // 注意顺序,应该先让要插入结点的指针域指向后一结点
    // 之后再断开前一结点与后一结点的指针,使前一结点指向要插入结点
    s->data = e; 
    s->next = p->next;
    //将结点s连到p后
    p->next = s;
    return true;
}

// 指定结点后插操作:在p结点之后插入元素e
// LNode强调为结点
bool InsertNextNode(LNode *p, int e) {
    // p不合理的情况
    if(p == NULL) {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    // 内存分配失败的情况
    if(s == NULL) {
        return false;
    }
    // 此处先将要插入结点的指针域指向前一个结点的指针域,即后一个结点的地址
    // 之后再令前一个结点的指针域指向要插入结点
    // 顺序不可颠倒,否则可能出现找不到之后结点的情况
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

// 指定结点前插操作:在p结点之前
// 此处可以通过一种特殊方法完成前插
// 本质上还是后插操作
bool InsertPriorNode(LNode *p, int e) {
    // p不合理的情况
    if(p == NULL) {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    // 内存分配失败的情况
    if(s == NULL) {
        return false;
    }
    // 插入操作
    // 通过将s插入p结点之后,然后将s结点与p结点的数据域进行互换
    // 可以视作完成了前插操作
    s->next = p->next;
    p->next = s;
    s->data = p->data;
    p->data =e;
    return true;
}

// 按位序删除
bool ListDelete(LinkList &L, int i, int &e) {
    // i不合理的情况
    if(i < 1) {
        return false;
    }
    LNode *p;   // 指针p指向当前扫描到的结点
    int j = 0;  // 当前p指向的是第几个结点
    // 初始令p指向头结点,即第0个结点
    p = L;
    // 通过遍历找到第i - 1个结点,即要删除结点的前驱结点
    while(p != NULL && j < i - 1) {
        p = p->next;
        j++;
    }
    // 若p等于NULL,则要么此链表为空,要么i值大于链表长度,显然不合理
    if(p == NULL) {
        return false;
    }
    // p->next为空表示第i-1个结点之后已经没有其他结点了,无法进行删除操作
    if(p->next == NULL) {
        return false;
    }
    // 删除操作
    // 就是将前驱结点指针域指向后继结点
    LNode *q = p->next;    
    e = q->data;
    p->next = q->next;
    // 不要忘记释放空间!!!
    free(q); 
    return true;
}

// 删除指定节点
// 类似于之前前插操作,一般情况下,显然必须先遍历找到前驱结点
// 或者类似于之前前插的第二种方法,来规避遍历
bool DeleteNode(LNode *p) {
    // p不合理的情况
    if(p == NULL) {
        return false;
    }
    // 此操作可以理解为将p节点与其后继结点进行数据域交换
    // 之后再删除其后继结点,可以视作完成了删除,且避免了寻找前驱结点的遍历操作
    // 注意:如果p是最后一个结点则会报错,因为p->next即是NULL,不能从NULL获取数据域
    // 此种情况,只能通过之前的遍历寻找前驱结点来完成删除操作
    // 类似于之前插入,在找到前驱结点后,删除操作与按位序删除相同
    LNode *q = p->next;
    p->data = p->next->data;
    p->next = q->next;
    free(q);
    return true;
}

// 按位查找,返回第i个元素
// 之前操作部分按位查找部分可以以此部分代码代替,提高代码复用性(封装)
LNode* GetElem(LinkList L, int i) {
    // 判断插入位序是否存在问题
    // 由于此是带头结点的情况,而头结点可以视作是第0个结点
    // 所以与之前遍历情况不同
    if(i < 0)
        return NULL;
    LNode *p;   // 指针p指向当前扫描到的结点
    int j = 0;  // 当前p指向的是第几个结点
    p = L;      // 初始令p指向头结点
    // 通过循环,找到第i个结点
    // 如果i大于链表长度,则找不到此节点,此时p指向最后结点的指针域,即NULL
    // 如果i初始为0,会直接返回头结点地址
    while(p != NULL && j < i) {
        p = p->next;
        j++;
    }
    return p;
}

// 按值查找,找到数据域等于e的结点
LNode* LocateElem(LinkList L, int e) {
    LNode* p = L->next;
    // 从第一个结点开始查找数据域为e的结点
    // 找不到,则会在遍历后指向NULL
    while (p != NULL && p->data != e) {
        p = p->next;
    }
    return p;
}

// 求表的长度
// 就是通过遍历所有结点,然后通过计数器来累加得到长度
int Length(LinkList L) {
    int len = 0;
    LNode* p = L;
    while(p->next != NULL) {
        p = p->next;
        len++;
    }
    return len;
}

// 尾插法
// 通过尾插法建立的链表,顺序为插入时元素的顺序
LinkList TailInsert(LinkList &L) {
    // 设置ElemType为整型
    int x;
    // 建立头结点(申请的空间为一个结点大小的空间)
    L = (LinkList)malloc(sizeof(LNode));
    // 初始化为空链表
    // 由于L在分配空间后,头指针可能并非指向NULL,而是其他任意区域,这可能导致问题发生
    // 动态分配的空间之前可能存在脏数据
    L->next = NULL;
    // 定义表尾指针
    // 对于尾插法,如果只通过头结点遍历的话
    // 每次插入时都要先遍历到表尾,时间复杂度为O(1+2+...+n-1)=O(n^2)
    // 所以选择增加一个尾指针,来避免遍历
    // s为要插入的结点,r为表尾指针
    LNode *s, *r = L;
    // 输入结点的值
    scanf("%d", &x);
    // 表示键入9999后建表结束
    while(x != 9999) {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        // r指向新的表尾结点
        r = s;
        // 继续输入下一个结点的值,直至输入9999结束
        scanf("%d", &x);
    }
    // 尾指针置空
    r->next = NULL;
    return L;
}

// 头插法
// 通过头插法建立的链表,顺序为插入时元素的逆序
LinkList HeadInsert(LinkList &L) {
    // 设置ElemType为整型
    int x;
    // 建立头结点(申请的空间为一个结点大小的空间)
    L = (LinkList)malloc(sizeof(LNode));
    // 初始化为空链表
    // 由于L在分配空间后,头指针可能并非指向NULL,而是其他任意区域,这可能导致问题发生
    // 动态分配的空间之前可能存在脏数据
    L->next = NULL;
    // 不同于尾插法,头插法无需定义更多指针
    LNode* s;
    // 输入结点的值
    scanf("%d", &x);
    // 表示键入9999后建表结束
    while(x != 9999) {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        // 继续输入下一个结点的值,直至输入9999结束
        scanf("%d", &x);
    }
    return L;
}

// 输出所有链表元素
void PrintList(LinkList L) {
    if(Empty(L)) {
        printf("the list is empty");
    }
    LNode* p = L->next;
    while(p !=  NULL) {
        printf("%d  ", p->data);
        p = p->next;
    }
    printf("\n");
}

int main() {
    LinkList L;
    InitList(L);
    TailInsert(L);
    PrintList(L);
    printf("get_2:%d\n",  GetElem(L, 2)->data);
    printf("locate_5:%d\n",  LocateElem(L, 5)->data);
    printf("length:%d\n", Length(L));
    InsertPriorNode(GetElem(L, 2), 7);
    PrintList(L);
    InsertNextNode(GetElem(L, 2), 5);
    PrintList(L);
    ListInsert(L, 3, 3);
    PrintList(L);
    int e;
    ListDelete(L, 3, e);
    PrintList(L);
    printf("e:%d\n", e);
}

3.运行截图

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【数据结构】【王道】【线性表】单链表的实现及基本操作(带头结点)(可直接运行) 的相关文章

  • VS2013多线程程序卡住以及各种异常的调试

    多线程程序 使用了锁 当卡住时 可以如下调试 点击 调试 全部中断 然后在 线程 窗口会显示当前运行的各个线程 以及他们的堆栈信息 这样就可以查看各个线程卡在哪里了 其它异常 VS蹦出一个异常窗口 类似如下 点击 重试 然后弹出如下窗口 点
  • 避坑10_VScode每次输入右上角都会有数字x累加

    一 问题 不知道什么原因 输入字符甚至ctrl s 右上角都会跳出一个数字x 一直累加 刚开始以为是git的修改提醒 但找来找去也没有发现在哪儿控制开关 十分烦躁 二 原因 插件Power Mode惹的祸 之前并未出现这种情况 但今天突然跳
  • CodeMirror用户手册

    用户手册和参考指南版本5 46 1 CodeMirror是一个代码编辑器组件 可以嵌入到Web页面中 核心库仅提供编辑器组件 不提供伴随按钮 自动完成或其他IDE功能 它确实提供了丰富的API 在此基础上可以直接实现这些功能 有关额外功能的
  • ipad鼠标怎么把圆圈换成箭头_高度融合,让iPad更像笔记本的金属键盘

    一直以来 都想给我的iPad配上一个键盘 这样在出行的时候 就不用带着厚重的笔记本电脑了 或者有些事情 可以直接用iPad解决 就不用再打开电脑 可能有人会说 为什么不直接用iPad上的虚拟键盘 用过的应该知道 iPad上的虚拟键盘 单手够
  • 12种排序算法详解

    作者 寒小阳 时间 2013年9月 出处 http blog csdn net han xiaoyang article details 12163251 声明 版权所有 转载请注明出处 谢谢 0 前言 从这一部分开始直接切入我们计算机互联
  • JavaScript -- 隐式类型转换

    文章目录 隐式类型转换 字符串拼接 使用 运算 if语句 总结 隐式类型转换 在JavaScript运算中 当运算符两边数据类型不一致时 编译器会自动将运算符两边的数据进行类型转换 转成一样的数据类型再进行计算 像这种由编译器自动完成数据类

随机推荐

  • .NET正则匹配模式

    1 概述 匹配模式指的是一些可以改变正则表达式匹配行为的选项或修饰符 不同的语言支持的匹配模式不同 使用的方式也不同 一般可分为全局和内联两种 下面主要介绍 NET中的匹配模式 其它语言的匹配模式 后续视情况补充 2 匹配模式 2 1 全局
  • 用 Python 分析《红楼梦》(2)

    6 词频统计 完成分词以后 词频统计就非常简单了 我们只需要根据分词结果把片段切分开 去掉长度为一的片段 也就是单字 然后数一下每一种片段的个数就可以了 这是出现次数排名前 20 的单词 括号内为频数 可以跟之前只统计出现次数 不考虑切分问
  • Linux上如何编译android apk——jdk、gradle、android sdk的安装与使用

    背景 Jenkins上目前需要增加对安卓流水线的支持 研究了下 发现核心流程就是通过gradle命令 来调用android sdk生成apk包 再把apk作为制品放到Jenkins上即可 环境准备 主要就三个 jdk gradle和andr
  • (二):C++求解文法的First集和Follow集

    功能及代码结构 为实现编译器前端 需要对文法进行分析 该部分实现从文件中读入文法 方便修改 用合适的数据结构表示并求解各个非终结符号的First集和Follow集 仓库 https github com xs1317 Complier 文件
  • java每日一题

    写两个函数 分别求两个整数的最大公约数和最小公倍数 用主函数调用这两个函数 并输出结果两个整数由键盘输入 输入格式 两个数 输出格式 最大公约数 最小公倍数 样例输入 6 15 样例输出 3 30 import java util Scan
  • Vue3.x中的Provider Inject

    我们可以使用 provide 和 inject 对父组件可以作为其所有子组件的依赖项提供程序 而不管组件层次结构有多深 这个特性有两个部分 父组件有一个 provide 选项来提供数据 子组件有一个 inject 选项来开始使用这个数据 s
  • 字符串的长度

    下面字符串的长度为 考点 转义字符 转义字符的意义 我们使用的字符串都是用 双引号框起来的 电脑只识别双引号内框起来的内容 printf 但是如果想表达的字符是 abc 即如下 printf abc 运行结果 报错 电脑是识别不出来具体哪段
  • pf_ring 5.4.0源码分析

    pf ring 5 4 0源码分析 pf ring是一款开源的高性能抓包库 项目的网址是 http www ntop org products pf ring 同经典的libpcap比较 pf ring提高性能的关键在以下三点 1 pf r
  • Kafka必须掌握的核心技术:java词法分析器代码

    二 常见的并发问题 1 脏读 一个事务读取了另一个事务未提交的数据 2 不可重复读 一个事务对同一数据的读取结果前后不一致 两次读取中间被其他事务修改了 3 幻读 幻读是指事务读取某个范围的数据时 因为其他事务的操作导致前后两次读取的结果不
  • 从今天起,将软件测试学习过程记录起来,一点一滴都要体现在这个博客中

    两年前 我开始做web开发 我的学习过程没有被记录下来 深感遗憾 今年2月28辞职 重新定了方向 做软件测试工作 我希望自己能在这里 记录自己技能成长的点点滴滴 既然选择了 路上再难 我也要坚持到底 不退缩
  • C++基础知识 - 纯虚函数与抽象类

    什么时候使用纯虚函数 某些类 在现实角度和项目实现角度 都不需要实例化 不需要创建它的对象 这个类中定义的某些成员函数 只是为了提供一个形式上的接口 准备让子类来做具体的实现 此时 这个方法 就可以定义为 纯虚函数 包含纯虚函数的类 就称为
  • ScheduledThreadPoolExecutor 及 ThreadPoolExecutor的基本使用及说明

    关于作者 CSDN内容合伙人 技术专家 从零开始做日活千万级APP 专注于分享各领域原创系列文章 擅长java后端 移动开发 人工智能等 希望大家多多支持 目录 一 导读 二 概览 2 1 为什么不推荐使用Executors去创建线程池 三
  • js创建文件发向服务器,Node.js创建HTTP文件服务器的使用示例

    HelloWorld示例只有演示意义 这次我们来搞一个实际的例子 文件服务器 我们使用Node js创建一个HTTP协议的文件服务器 你可以使用浏览器或其它下载工具到文件服务器上下载文件 为了读取文件 我们会用到File System模块
  • 素数p阶群乘法循环群啥意思_如何证明素数阶群都是abel群?

    这个证明需要分两步 1 首先证明素数阶群都是循环群 2 其次证明循环群一定是abel群 我先来证明1 过程如下 首先我们假设p为任意素数 存在一个群G 群G的阶数是 G p 根据拉格朗日定理我们知道 G的所有元素的阶都可以被p整除 这里的关
  • openGauss5.0企业版CentOS一主两从安装

    目录 一 前期规划 二 依赖包安装 三 环境配置 四 安装前准备 五 预安装 六 安装 一 前期规划 主机名 IP CPU 内存 操作系统 python 节点 node4 192 168 5 7 2核 4G CentOS 7 9 3 6 8
  • yolo格式、voc格式、coco格式相互转换(xml,json,txt)

    yolo转voc keras版yolov3训练格式是name box class这种形式 转voc格式使用一下代码 根据别人的代码改了一点 list txt为yolo的标签 转换的voc格式的标签为 xml文件 都存放在Annotation
  • 计算机程序的构造和解释习题3.28

    计算机程序的构造和解释习题3 28 问题 请将或门定义为一个基本功能块 令构造函数为or gate 程序 define or gate in1 in2 out define or action procedure let new value
  • CH4-程序活动单元Activity

    文章目录 目标 一 Activity的生命周期 目标 1 1 生命周期状态 1 2 生命周期方法 二 Activity的创建 配置 启动和关闭 目标 2 1 创建Activity 2 2 配置Activity 2 3 启动和关闭Activi
  • 点击按钮复制想要复制的文字, 三行代码搞定。。 想粘贴到哪里就粘贴到哪里。。...

    UIPasteboard pab UIPasteboard generalPasteboard NSString string 这个方法走完之后有文本框的时候长按就可以粘贴啦 pab setString string 转载于 https w
  • 【数据结构】【王道】【线性表】单链表的实现及基本操作(带头结点)(可直接运行)

    总目录 文章目录 1 基本操作 1 1 结构体定义 1 2 初始化 1 3 判空 1 4 按位序插入 1 5 指定结点后插操作 1 6 指定结点前插操作 1 7 按位序删除 1 8 按位查找 1 9 按值查找 1 10 表的长度 1 11