线性表

news2024/9/28 22:10:00

1.1线性表的定义

 线性表:零个或多个数据元素的有限序列。

注:

        (1)它是一个序列。元素之间是有顺序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他元素有且只有一个前驱和后继。

        (2)有限。元素个数是有限的。

将线性表记为\left ( a_{1}, \cdots ,a_{i-1},a_{i},a_{i+1},\cdots ,a_{n}^{}\right )

由图可以看到,a_{i-1}a_{i}直接前驱元素a_{i+1}a_{i}直接后继元素

线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,称为空表

若 a_{1}是第一个元素,a_{n}是最后一个,第i个元素是a_{i},i叫做a_{i}线性表中的位序

在较复杂的线性表中,一个数据元素可以由若干个数据项组成。

1.2线性表的抽象数据类型

线性表的操作:创建和初始化、重置为空表、根据位序得到数据元素、查找、表长、插入删除数据。

抽象数据类型定义:

ADT 线性表(List)

Data

        线性表的数据集合为\left ( a_{1}, \cdots ,a_{i-1},a_{i},a_{i+1},\cdots ,a_{n}^{}\right ),每个元素类型均为DataType。其中,除了a_{1},其他元素都有且仅有一个直接前驱,除了a_{n},其他元素都有且仅有一个直接后继。数据元素之间的关系是一对一的关系。

Operation

        InitList(*L);        初始化操作,建立一个空的线性表L

        ListEmpty(L);        若线性表为空,返回true,否则返回false

        ClearList(*L);        线性表清空

        GetElem(L, i, *e);        将线性表L的第i个位置元素值返回给e

        LocateElem(L, e);        在线性表L中查找与e相等的元素,查找成功,返回表中序列,否则返回0

        ListInsert(*L, i, e);        在线性表L中的第i个位置插入元素e

        ListDelete(*L, i, e);        删除线性表L中第i个位置的元素,并用e返回其值

        ListLength(L);        返回线性表L中的元素个数

endADT

例:实现线性表集合A和B的并集操作。

        思路:把存在在B集合但不存在在A集合的元素插入到A中,循环集合B,判断元素是否存在在A集合中,不存在则插入。

void union(SqList *La, SqList Lb)
{
    int La_len, Lb_len, i;
    ElemType e;                            /*声明与La和Lb相同的数据元素e*/
    La_len = ListLength(*La);              /*求线性表的长度*/
    Lb_len = ListLength(Lb);
    for(i = 1; i <= Lb_len; i++)
    {
        GetElem(Lb, i &e);                 /*取Lb中第i个数据元素赋给e*/
        if(!LocateElem(*La, e))            /*La中不存在和e相同的数据元素*/
            ListInsert(La, ++La_len, e);   /*插入*/
    }
}

注:

当传递一个参数给函数时,这个参数会不会在函数内被改动决定了使用什么参数形式。

如果需要被改动,则需要传递指向这个参数的指针。

如果不需要被改动,可以直接传递这个参数。

1.3线性表的顺序存储结构

1.3.1顺序存储定义

线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。

顺序存储示意图:

1.3.2顺序存储方式

顺序存储结构将一片连续空间占了,将相同数据类型的数据元素依次存放在这块空间。使用一维数组来实现顺序存储结构,即第一个元素存放在下标为0的位置(起始位置),然后依次存放

这个数组的长度就是顺序存储的最大容量,线性表长度不能超过最大存储容量。

顺序存储结构代码:

#define MAXSIZE 20            /*存储空间初始分配量*/
typedef int ElemType          /*ElemType类型清空而定*/
typedef struct                
{
    ElemType data[MAXSIZE];   /*数组,存储数据元素*/
    int length;               /*线性表当前长度*/
}SqList;

描述顺序存储结构需要三个属性:

(1)存储空间起始位置:数组data,它的存储位置就是存储空间的存储位置。

(2)线性表的最大容量:数组长度MAXSIZE。

(3)线性表的当前长度:length。

1.3.3数组长度和线性表长度的区别

数组长度是指存放线性表的存储空间的长度,存储分配后这个量一般是不变的。

线性表长度是指线性表中数据元素的个数,会随着线性表的删除和插入操作变化。

在任意时刻,线性表的长度都应该小于等于数组的长度。

1.3.4地址计算方法

线性表从1开始,数组从0开始,即:线性表的第i个元素存储在数组下标为i-1的位置。 

存储器中的每个存储单元都有自己的编号,这个编号叫做地址。

假设每个数据元素占用的是c个存储单元,那么线性表中的第i+1和第i个数据元素的存储位置满足:

LOC\left ( a_{i+1} \right )=LOC\left ( a_{i} \right )+c

LOC\left ( a_{i} \right )=LOC\left ( a_{1} \right )+\left ( i-1 \right )*c

时间性能为O(1)这一特点的存储结构称为随机存储结构

1.4顺序存储结构的插入与删除

1.4.1获得元素操作

将线性表L中的第i个位置元素返回。即:将i的数值在数组下标范围内,把数组第i-1下标位置的值返回。

#define OK 1
#define ERROR 0
/*Status是函数的类型,其值是函数结果状态代码,如OK等*/
typedef int Status;

/*操作结果:用e返回L中第i个数据元素*/
Status GetElem(SqList L, int i, ElemType *e)
{
    if(L.length == 0 || i < i || i > L.length)
        return ERROR;
    *e = L.data[i - 1];

    return OK; 
}

1.4.2插入操作

ListInsert(*L,i,e),即在线性表L中的第i个位置插入新元素e。

思路:(1)如果插入位置不合理,抛出异常。

           (2)线性表长度大于等于数组长度,抛出异常或动态增加容量。

           (3)从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置。

           (4)将要插入元素填入位置i处。

           (5)表长加1。

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L),*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度假1*/
Status ListInsert(SqList *L, int i,ElemType e)
{
    int k;
    if(L -> length == MAXSIZE)    /*线性表已满*/
        return ERROR;
    if(i < 1 || L -> length + 1)    /*i比第1个位置小或比最后一个位置大*/
        return ERROR;
    if(i <= L -> length)
    {
        for(k = L -> length - 1; k >= i - 1; k--)
            L -> data[k + 1] = L -> data[k];
    }
    L -> data[i - 1] = e;
    L -> length++;

    return OK;
}

 1.4.3删除操作

思路:(1)如果删除位置不合理,抛出异常

           (2)取出删除元素

           (3)从删除元素位置开始遍历最后一个元素位置,分别将它们都向前移动一个位置。

           (4)表长减1。

Status ListDelete(SqList *L, int i, ElemType e)
{
    int k;
    if(L -> length == 0)
        return ERROR;
    if(i < 1 || i > L -> length)
        return ERROR;
    *e = L-> data[i - 1];
    if(i < L -> length)
    {
        for(k = i; k < L -> length; k++)
            L ->data[k - 1] = L -> data[k];
    }
    L -> length--;
    return OK;
}

插入删除操作时间复杂度:

(1)插入删除操作位于最后一个位置,时间复杂度为O(1),因为不需要移动元素。

(2)对第一个位置元素进行插入删除操作,时间复杂度为O(n),因为要移动所有的元素。

(3)平均情况,,元素插入到第i个位置,删除第i个元素,需要移动n-i个元素。最终平均移动次数和最中间的元素的移动次数相等,为(n-1)/2。时间复杂度为O(n)。

综上:线性表的顺序存储结构在读取数据时,时间复杂度是O(1),插入和删除操作时,时间复杂度是O(n)。

1.4.4线性表顺序存储结构的优缺点

1.5线性表的链式存储结构

1.5.1定义

特点:用一组任意的存储单元线性表的数据元素,存储单元是任意的,可以连续也可以不连续,这些数据元素可以存在内存中未被占用的任意位置。

为了表示数据元素a_{i}和直接后继数据元素a_{i+1}之间的逻辑关系,对于a_{i},在存储数据元素本身以外,还需要存储一个指示其直接后继的存储位置。存储数据元素信息的域称为数据域,存储直接后继位置的域叫做指针域。指针域中存储的信息叫做指针。这两部分信息组成数据元素a_{i}存储映像,称为结点

n个结点链结成一个链表,即为线性表的链式存储结构,每个结点中只包含一个指针域,所以叫单链表。单链表通过每个结点指针域将数据元素按逻辑次序链接在一起。

链表中的第一个结点的存储位置叫做头指针,整个链表的存取就必须从头指针开始进行。链表的最后一个结点的指针为空(NULL或 ^ )。

为了方便操作,在单链表的第一个结点前设一个头节点。数据域可以不存储任何信息,也可以存线性表长度等公共数据,头节点的指针域存储指向第一个结点的指针。

1.5.2头指针与头节点

头指

1.是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。

2.具有标志作用,所以常用头指针冠以链表名字。

3.无论链表是否为空,头指针均不为空。头指针是链表的必要条件。

头结点

1.是为了操作的统一和方便设立,放在第一元素的结点之前,其数据域一般无意义。

2.有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作统一。

3.不是链表必要元素。

1.5.3代码描述

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

/*线性表的单链表存储结构*/
typedef struct Node
{
    ElemType data;
    struct Node *next;
}Node;
typedef struct Node *LinkList

结点由存放数据元素的数据域和存放后继结点地址的指针域组成。设p是指向线性表第i个元素的指针,则使用p->data的值表示结点a_{i}的数据域,p->next表示a_{i}指针域,p->next指向a_{i+1}。如果p    -->data=a_{i},那么p->next->data=a_{i+1}

1.

1.6单链表的读取

获取第i个元素的数据操作

思路:

        (1)声明一个指针p指向链表的第一个结点,初始化j从1开始;

        (2)当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1;

        (3)若到链表末尾p为空,则说明第i个结点不存在;

        (4)否则查找成功,返回结点p的数据。

/*操作结果:用e返回L中第i个数据元素的值*/
Status GetElem(LinkList L, int i, ElemType *e)
{
    int j;
    LinkList p;    //声明一个指针p
    p = L -> next;    //让p指向L的第1个结点
    j = 1;    //j为计数器
    while(p && j < i)    //p不为空或者计数器j还没等于i,循环继续
    {
        p = p -> next;    //让p指向下一结点
        ++j;
    }
    if (!p || j > i)
        return ERROR;    //第i个元素不存在
    *e = p -> data;    //取第i个元素的数据
    return OK;
}

1.7单链表的插入和删除

1.7.1单链表的插入

假设存储元素e的结点为s,将s插入到p和p->next中间

将p的后继结点赋值给s的后继,然后将s的值赋给p的后继。

s -> next = p -> next;
p -> next = s;

二者位置不能互换位置。单链表表头表尾操作相同。

单链表第i个数据插入结点算法思路:

(1)声明一指针p指向链表头结点,初始化j从1开始;

(2)当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1;

(3)若到链表末尾p为空,则说明第i个结点不存在;

(4)否则查找成功,在系统中生成一个空结点s;

(5)将数据元素e赋值给s->data;

(6)单链表的插入标准语句s->next=p->next;        p->next=s;

(7)返回成功。

//在L中第i个位置之前插入新的数据元素e,L元素加1
Status(LinkList *L, int i, ElemType e)
{
    int j;
    LinkList p, s;
    p = *L;
    j = 1;
    while(p && j < i)    //寻找第i个结点
    {
        p = p -> next;
        ++j;
    }
    if(!p || j > i)
    return ERROR;    //第i个元素不存在

    s = (LinkList)malloc(sizeof(Node));    //生成新结点
    s -> data = e;
    s -> data = p -> next;    //将p的后继结点赋值给s的后继结点
    p -> next = s;    //将s的值赋值给p的后继
    return 0;
}

1.7.2单链表的删除

p -> next = p -> next -> next,用q取代p -> next,即:

q = p ->next;
p -> next = q -> next;

思路:

(1)声明一指针p指向表头结点,初始化j从1开始;

(2)当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1;

(3)若到链表末尾p为空,则说明第i个结点不存在;

(4)否则查找成功,将欲删除的结点p->next赋值给q;

(5)单链表删除标准语句p->next=q->next;

(6)将q结点中的数据赋值给e,作为返回;

(7)释放q结点;

(8)返回成功。

Status(LinkList *L, int i, ElemType e)
{
    int j;
    LinkList p, q;
    p = *L;
    j = 1;
    while(p ->next && j < i)
    {
        p = p -> next;
        ++j;
    }
    if(!(p -> next) || j > i)
        return ERROR;
    
    q = p ->next;
    p -> next = q -> next;
    *e = q -> data;
    free(q);
    return OK;
}

对于插入删除数据频繁的操作,单链表的效率优势就越明显。

1.8单链表的整表创建

单链表是一种动态结构,它所占用空间大小和位置是不需要预先分配划分,可以根据系统的情况和实际需求即使生成。

创建单链表的过程就是动态生成链表的过程。即从“空表”的初始状态起,依次建立各元素结点,并逐个插入链表。

思路:

(1)声明一指针p和计数器变量i;

(2)初始化空链表L;

(3)让L的头结点的指针指向NULL,即建立一个带头结点的单链表。

(4)循环:

        1.生成一新结点赋值给p

        2.随机生成一数字赋值给p的数据域p->data

        3.将p插入到头结点与前一新结点之间。

头插法:

void CreateListHead(LinkList *L, int n)
{
    LinkList p;    
    int i;
    srand(time(0));    //随机数种子
    *L = (LinkList)malloc(sizeof(Node));
    (*L) -> next = NULL;    //先建立一个带头结点
    for(i = 0; i < n; i++)
    {
        p = (LinkList)malloc(sizeof(Node));    //生成新结点
        p -> data = rand () % 100 + 1;    //随机生成100以内的数字
        p -> next = (*L) -> next;
        (*L) -> next = p;    //插入到表头
    }
}

采用的是插队的方法,始终让新结点在第一的位置。

尾插法:

void CreateListHead(LinkList *L, int n)
{
    LinkList p;    
    int i;
    srand(time(0));    //随机数种子
    *L = (LinkList)malloc(sizeof(Node));
    r = *L;    //r为指向尾部的结点
    for(i = 0; i < n; i++)
    {
        p = (Node*)malloc(sizeof(Node));    //生成新结点
        p -> data = rand () % 100 + 1;    //随机生成100以内的数字
        r -> next = p;    //将表尾终端结点的指针指向新结点
        r = p;    //将当前的新结点定义为表尾终端结点
    }
    r -> next = NULL;    //链表结束
}

将新结点放在最后。L是指整个单链表,r是指向尾结点的变量,r会随循环不断变化的结点,L随着循环增长为一个多结点的链表。

r->next=p的意思是将刚才的表尾终端结点r的指针指向新结点p。

r=p是让r重新称为尾结点。

此时r为尾结点,那么循环结束后,让这个结点的指针域置空,即:r ->next=NULL。

1.9单链表的整表删除

单链表的销毁,思路:

(1)声明一个指针p和q;

(2)将第一个结点赋值给p;

(3)循环:

        1.将下一结点赋值给q;

        2.释放p;

        3.将q赋值给p;

Status(LinkList *L)
{
    LinkList p, q;
    int i;
    p = (*L) -> next;    //p指向第一个结点
    while(p)    //没到表尾
    {
        q = p -> next;
        free(p);
        p = q;
    }
    (*L) -> next = NULL;    //头结点指针域为空
    return OK;
}

1.10单链表结构与顺序存储结构的优缺点

分配方式

顺序存储结构用一段连续的存储单元依次存储线性表的数据元素。

单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素。

时间性能

查找

        顺序存储:O(1)

        单链表:O(n)

插入和删除

        顺序存储结构需要平均移动表长的一半,O(n)

        单链表找到指针位置后,插入删除时间复杂度仅为O(1)

空间性能

顺序存储结构需要预先分配空间,大了浪费,小了溢出。

单链表不预先分配存储空间,有空就分配,元素个数不受限。

即:若线性表需要频繁查找,不怎么进行插入删除操作,宜使用顺序存储结构;若要频繁进行插入删除操作,不频繁查找,更适合使用单链表。

1.11静态链表

让数组的元素都由两个数据域组成,data和cur。data用来存储数据元素,cur相当于单链表中的next指针。用数组描述的链表叫做静态链表。

#define MAXSIZE 1000
typedef struct
{
    ElemType data;
    int cur;    //为0时无指向
}Component,StaticList[MAXSIZE]

对数组第一个和最后一个元素作为元素处理,不存数据。把未被使用的数组元素称为备用链表。

//将一维数组space中各分量链成,space[0].cur为头指针,0表示空指针
Status InitList(StaticLinkList space)
{
    int i;
    for(i = 0; i < MAXSIZE - 1; i++)
        space[i].cur = i + 1;
    space[MAXSIZE - 1].cur = 0;    //目前静态链表为空,最后一个cur为0
    return 0;
}

假设已经将数据存入静态数组,如下图所示:

1.11.1静态链表的插入操作

 主要要解决如何用静态模拟动态链表结构的存储空间分配,需要时申请,无用时释放。

动态链表使用malloc()和free(),但是静态链表不存在,需要我们自己实现这两个函数才能插入和删除。

//若备用空间链表非空,则返回分配的结点下标,否则返回0
int Malloc_SSL(StaticLinkList space)
{
    int i = space.[0].cur;    //当前数组第一个元素的cur存的值
    if(space[0].cur)    
        space[0].cur = space[i].cur;
    return i;    
}

这段代码的一个作用就是返回一个下标值,这个值是数组头元素的cur存的第一个空闲的下标。

实现插入操作:

Status ListInsert(StaticLinkList L, int i, ElemType e)
{
    int j, k, l;
    k = MAXSIZE - 1;    //k首先是最后一个元素下标
    if(i < 1 || i > ListLenght(L) + 1)
        return ERROR;
    j = Malloc_SSL(L);    //获得空闲分量的下标
    if(j)
    {
        L[j].data = e;    //将数据赋值给此分量的data
        for(l = 1; l <= i -1; l++)    //将数据赋值给data
            k = L[k].cur;
        L[j].cur = L[k].cur;    //把第i个元素之间的cur赋值给新的cur
        L[k].cur = j;    //把新元素的下标赋值给第i个元素之前元素的cur
        return OK;
    }
    return ERROR;
}

1.11.2静态链表的删除操作 

//删除L中的第i个数据元素
Status ListDelete(StaticLinkList L, int i)
{
    int j, k;
    if(i < 1 || i > ListLength(L))
        return ERROR;
    k = MAXSIZE - 1;
    for(j = 1; j <= i - 1; j++)
        k = L[k].cur;
    j = L[k].cur;
    L[k].cur = L[j].cur;
    Free_SSL(L, j);
    return OK;
}
//将下标为k的空间结点回收到备用链表
void Free_SSL(StaticLinkList space, int k)
{
    space[k].cur = space[0].cur;    //把第一个元素cur值赋给要删除的分量cur
    space[0].cur = k;    //把要删除的分量下标赋值给第一个元素的cur
}

这个意思是A走了,然后这个位置空了出来,如果有新的元素进来,最优先考虑这个位置,所以原来的第一个空位分量就是下标为8的分量,让要删除的这个位置成为第一个优先空位。

1.11.3优缺点

优点:在插入和删除时只需要改变游标不需要移动位置,改进了需要移动大量元素的缺点。

缺点:失去随机存储的特性,没有解决表长问题。

1.12循环链表

头尾相接的单链表称为循环链表。

循环链表解决了如何从当中一个结点出发,访问到链表的全部结点。

为使空链表与非空链表处理方式一致,设一个头结点。

空链表:

非空循环链表:

p->next不等于头结点,则循环未结束。

使用指向终端结点的尾指针表示循环链表可以很方便的查找到开始和终端结点。

终端结点用尾指针rear表示,开始结点:rear->next->next

将两个循环链表合并成一个表:

p = rearA -> next;    //保存A表的头结点
rearA -> next = rearB -> next -> next;    //将本指向B表的第一个结点赋值给rearA->next

q = rearB -> next;    
rearB -> next = p;    //将原A表的头结点赋值给rearB -> next
free(q);

1.13双向链表

双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接前驱,一个指向直接后继。

//线性表的双向链表存储结构
typedef struct DulNode
{
    ElemType data;
    struct DulNode *prior;    //直接前驱指针
    struct DulNode *next;    //直接后继指针
}DulNode, *DuLinkList;

空链表:

非空双向循环链表:

双向链表某个结点p的后继的前驱是它自己。

p -> next -> prior = p = p -> prior -> next

插入和删除时需要改变两个指针变量

存储元素e的结点s,插入到p和p ->next之间

s -> prior = p;    //把p赋值给s的直接前驱
s -> next = p -> next;    //把p->next赋值给s的直接后继
p -> next -> prior = s;    //把s赋值给p->next的前驱
p -> next = s;    //把s的值赋给p的后继

 删除结点p

p -> prior -> next = p -> next;    //把p->next赋给p->prior的后继
p -> next -> prior = p -> prior;    //把p->prior赋值给p->next的前驱
free(p);

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

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

相关文章

SpringBoot 使用logback(多环境配置)

Logback是由log4j创始人设计的又一个开源日志组件。可用于项目日志功能。官网地址 第1步&#xff1a;添加坐标依赖 <!--logback--> <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version…

该问题未得到解决(仅记录)

https://releases.ubuntu.com/bionic/进入网页下载ubuntu 选择烧录软件将下载的Ubuntu烧录到U盘中 之前用这个U盘烧录过一次&#xff0c;成功了&#xff0c;后来应该是U盘受损或者是什么其他原因使得用这个U盘总是烧录失败

网安面经之xss漏洞

目录 一、XSS漏洞 1、xss漏洞原理与危害 2、xss的类型&#xff1f;区别&#xff1f;修复&#xff1f; 3、常见使用的标签&#xff0c;payload构造 一、XSS漏洞 1、xss漏洞原理与危害 原理&#xff1a;xss就是跨站脚本攻击漏洞&#xff0c;也可以理解为前端的代码注入&…

数字人金融应用技术指南

根据《北京金融科技产业联盟团体标准管理办法》的规定&#xff0c;2024年3月27日经北京金融科技产业联盟第三届理事会第二次会议审议&#xff0c;批准发布《数字人金融应用技术指南》&#xff08;T/BFIA 027—2024&#xff09;、《图数据库金融应用技术要求》&#xff08;T/BFI…

医院转型新突破:精益六西格玛助力管理费大降13%,业务飙升26%

近年来&#xff0c;越来越多的医院开始尝试引入精益六西格玛管理模式&#xff0c;以期实现管理费的降低和业务量的增长。那么&#xff0c;精益六西格玛模式真的有这么牛吗&#xff1f;深圳天行健六西格玛培训公司将从实践角度出发&#xff0c;探讨精益六西格玛如何助力医院实现…

GAME101-Lecture06学习

前言 上节课主要讲的是三角形的光栅化。重要的思想是要利用像素的中心对三角形可见性的函数进行采样。 这节课主要就是反走样。 课程链接&#xff1a;Lecture 06 Rasterization 2 (Antialiasing and Z-Buffering)_哔哩哔哩_bilibili 反走样引入 ​ 通过采样&#xff0c;得到…

Vuex核心概念-state状态

目录 一、目标 二、提供数据 三、使用数据 1.通过store直接访问 2.通过辅助函数&#xff08;简化&#xff09; 一、目标 明确如何给仓库提供数据&#xff0c;如何使用仓库的数据 二、提供数据 State提供唯一的公共数据源&#xff0c;所有共享的数据都要统一放到Store中的…

了解 条码工具 Dynamsoft 在条码读取器中的形态运算

在图像处理中&#xff0c;术语形态学是指分析形状以填充小孔、去除噪声、提取轮廓等的一组操作。形态学操作很像空间卷积中的过滤过程。有两个部分在起作用&#xff1a;结构元素和预定义的计算规则。 点击下载Dynamsoft最新版https://www.evget.com/product/3691/download 结…

C#上位机1ms级高精度定时任务

precisiontimer 安装扩展包 添加引用 完整代码 using PrecisionTiming;using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; us…

Java数组(二)

Java数组&#xff08;二&#xff09; 1、多维数组 多维数组可以看成是数组的数组&#xff0c;比如二维数组就是一个特殊的一维数组&#xff0c;其每一个元素都是一个一维数组。二维数组 int a[][] new int[2][5];解析&#xff1a;以上二维数组a可以看成一个两行五列的数组。…

七、Redis三种高级数据结构-HyperLogLog

Redis HyperLogLog是用来做基数统计的算法&#xff0c;HyperLogLog在优点是&#xff0c;在输入的元素的数量或者体积非常大时&#xff0c;计算基数占用的空间总是固定的、并且非常小。在Redis里每个HyperLogLog键只需花费12KB内存&#xff0c;就可以计算接近 264 个元素的基数。…

政安晨【零基础玩转各类开源AI项目】:基于Ubuntu系统本地部署使用GPT-SoVITS进行语音克隆与TTS语音生成

目录 介绍 什么是TTS 安装Miniconda 框架功能 测试通过的环境 开始 1. 安装好miniconda 2. 进入下载的GPT-SoVITS目录 3. 创建虚拟环境并执行脚本 4. 执行过程中可能会出错 5. 下载预训练模型 6. 训练过程中可能会报错 7. 使用过程中可能出错 8.以下是使用全过程…

Java入门基础学习笔记8——注释

1、注释&#xff1a; 注释是写在程序中对代码进行解释说明的文件&#xff0c;方便自己和其他人查看&#xff0c;以便理解程序的。 package cn.ensource.note;/**文档注释文档注释 */ public class NoteDemo {public static void main(String[] args) {// 单行注释System.out.…

Vue从入门到实战Day04

一、组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; 1. scoped样式冲突 默认情况&#xff1a;写在组件中的样式会全局生效 -> 因此很容易造成多个组件之间的样式冲突问题。 1. 全局样式&#xff1a;默认组件中的样式会作用到全局 2. 局部样式&#xff1a;可以…

电脑开机显示器不亮?3大原因及解决办法

电脑开机后&#xff0c;显示器不亮是一个常见的问题&#xff0c;可能会给用户带来困扰。然而&#xff0c;这个问题通常并不复杂&#xff0c;可以通过一些简单的方法来解决。在本文中&#xff0c;我们将介绍三种常见的方法&#xff0c;帮助您解决电脑开机显示器不亮的情况。这些…

AI作画涉及的深度学习算法

AI作画中使用的深度学习算法多种多样&#xff0c;这些算法主要基于神经网络的结构和训练方式&#xff0c;以生成和改进艺术作品。以下是一些在AI作画中常用的深度学习算法&#xff1a; 生成对抗网络&#xff08;GANs, Generative Adversarial Networks&#xff09;&#xff1a…

vue3 antd-vue 超简单方式实现a-table跨页勾选

一、效果如下&#xff1a; 第一页勾选了2&#xff0c; 3&#xff0c; 4 翻到第三页勾选24&#xff0c; 25 回显&#xff0c;如比返回第一页的时候触发分页改变&#xff0c; 在映射中的第一页的数据给到a-table绑定的state.selectedRowKeys即可&#xff0c;如下方法 二、勾选思路…

【深度学习】Diffusion扩散模型原理解析1

1、前言 diffusion&#xff0c;这几年一直很火的模型&#xff0c;比如这段时间在网上的文生图大模型——Stable diffusion。就是以diffusion作为基底模型&#xff0c;但由于该模型与VAE那边&#xff0c;都涉及了较多了概率论知识&#xff0c;实在让人望而却步。所以&#xff0…

idea-自我快捷键-2

1. 书签 创建书签&#xff1a; 创建书签&#xff1a;F11创建特色标记书签&#xff1a;Ctrl F11快速添加助记符书签&#xff1a;ctrl shift 数字键 查看书签&#xff1a; shift F11快速定位到助记符书签&#xff1a;Ctrl 数字键 删除书签&#xff1a; delete 2. 自动…

Android使用Chaquo来运行Python的librosa的相关代码【有详细案例教程】

在某些情况下&#xff0c;我们可能需要在android上运行python的代码&#xff0c;那么常见的解释器有很多&#xff0c;目前比较成熟的就是chaquo&#xff0c;它适配的第三方机器学习的库很多&#xff0c;下面是它的简单使用教程 1.环境的搭建 1.1 在Android studio中新建安卓工…