数据结构笔记1线性表及其实现

news2024/12/23 8:32:49

终于开始学习数据结构了 c语言结束之后 我们通过题目来巩固了 接下来我们来学习数据结构

这里我们将去认识到数据结构的一些基础知识,我在第一次学习的时候会很迷糊现在重新学习发现之前的时候还是因为c语言学的不牢固导致学习数据结构困难 这里 我会尽量的多写代码注释

目录

一什么是数据结构?

二线性表

2.1概述

2.2特点

2.3储存方式

2.4线性表的基本操作

2.5线性表的顺序存储结构

2.5.1概述

2.5.2 创建顺序线性表

2.5.3获得元素操作

2.5.4插入操作

2.5.6删除操作

2.6线性表的链式存储结构

2.6.1概述

2.6.2 单链表的建立

 2.6.3单链表的读取

2.6.4单链表的插入

 2.6.5单链表的删除

2.6.6链表的整表删除


一什么是数据结构?

1.1 概述:指互相之间存在着一种或多种特定关系的数据元素的集合,包括逻辑结构,存储结构和对数据的运算。(数据元素都不是孤立存在的)

二线性表

2.1概述

:0个或多个数据元素的有限序列 

2.2特点

               1 元素之间是有顺序的 

                2 若元素存在多个,则第一个元素无前驱,最后一个元素无后驱 其他每个元素有且只有一个前驱和后驱

                3 元素的个数是有限的

2.3储存方式

                       顺序储存

                      链式储存

2.4线性表的基本操作

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返回其值

LiseLength(L):返回线性表L的元素个数

这里的基本操作 后面我们会都写出来的

2.5线性表的顺序存储结构

2.5.1概述

:用一段地址连续的储存单元依次储存线性表的数据元素

那说到这里的定义,大家是不是会联想到数组 数组的定义:数组由数据类型相同的一系列元素组成 即开辟一块内存空间 给数组 数组每相邻的元素不仅逻辑上相邻物理地址上也是相邻的

是不是和线性表的顺序储存结构一样 所以我们利用数组来完成线性表的顺序储存

我们来看线性表的顺序储存的结构代码

#define MAXSIZE 20 /*储存空间初始分配量 值无具体要求看线性表的大小*/
typedef int ElemType;/*这里我们将int类型取个别名为ElemType 
                      方便我们后面对线性表的类型进行定义 
                      ElemType也就是线性表的类型根据实际情况定,这里以int举例*/
typedef struct
{
    ElemType data[MAXSIZE]; //数组储存数据元素,最大值为MAXSIZE
    int length;
}Sqlist;//定义了一个结构体类型,别名为Sqlist 

这里我们发现描述顺序存储结构需要三个属性:

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

2 线性表的最大存储空间:数组的长度MAXSIZE

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

我们再来补充一点:数据长度和线性表长度的区别

数组的长度是存放线性表的储存空间的长度,存储分配后一般不变,除非是动态分配

线性表的长度是线性表中数据元素的个数 伴随着线性表的插入和删除操作的进行这个量会进行改变。

简单的说呢 线性表存放在数组里面 但不一定是达到最大值存放的 所以线性表的长度是小于或等于数组的长度

这里我们举个例子,比如数组data[5] 数组的长度是5 线性表只有俩个元素 只用到了俩个数组元素

所以线性表的长度是2

2.5.2 创建顺序线性表

我们来通过示例来创建一个线性表

#include <stdio.h>
#define MAXSIZE 5 //这里我们举例就不用那么大的了 最大为5
typedef struct 
{
    int data[MAXSIZE];
    int length;
}Sqlist; /*这里的注释上面有 我就不提了*/
/*初始化线性表函数 我们需要对线性表进行操作 所以将线性表的地址传入进来
  通过指针对线性表进行操作*/
void Initlist(Sqlist *L)
{
    L->length=5;//线性表的长度为5
    for(int i=0;i<5;i++)//将线性表的每个元素都赋值
    {
        L->data[i]=i+1;
    }
}

int main()
{
    Sqlist L;//建立一个线性表
    Initlist(&L);//初始化线性表
    for(int i;i<5;i++)//输出线性表的每个元素
    {
        printf("L.data[i]=%d\n",L.data[i]);
    }
    return 0;
}

这里需要特别注意,我们需要对线性表进行初始化,传入函数的参数一定不能错了 需要通过指针去操作的,这里我们的一个线性表就创建好了 我们将来一一介绍对线性表的操作

上面有过注释的 下面的代码 很有可能就不带了 大家需要一步一步的去理解 每一部分的注释我肯定都会写过的

2.5.3获得元素操作

概述:返回线性表L中的第i个元素的值

思路:就是将线性表的指定位置的值给输出出来

#include <stdio.h>
#define MAXSIZE 5 
typedef struct 
{
    int data[MAXSIZE];
    int length;
}Sqlist;
void Initlist(Sqlist *L)
{
    L->length=5;
    for(int i=0;i<5;i++)
    {
        L->data[i]=i+2;
    }
}
//获得指定位置元素的值,参数是L 和指定位置比如指定获得线性表第二个元素的值
int GetElem(Sqlist L,int i)
{
    if(L.length==0 || i<1||i>L.length)//防止意外情况 返回0 即错误
        return 0;
    else
    {
        return i-1;/*在查找操作正确的时候,返回指定值的数组下标 因为数组下标是从0开始的 
                     第2个元素的数组下标实际上是1所以返回指定位置-1即是数组的下标*/
    }
}
int main()
{
    Sqlist L;
    Initlist(&L);
    for(int i=0;i<5;i++)
     {
        printf("L.data[i]:%d\n",L.data[i]);
     }
    int a;
    a=GetElem(L,2);//用a来接收GetElem的值 并判断是否查找正常
    if(a)
    {
      printf("指定位置的值是%d\n",L.data[a]);       
    }
    else
     printf("获取指定位置的值出现错误 ");
    return 0;
}

2.5.4插入操作

概述:在线性表L中的第i个位置插入新元素e

思路:1 如果插入位置不合理,即错误

           2 如果线性表的长度等于数组的长度时即饱和了 无法进行插入 即错误除非动态增加容量

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

           4 表长加1

代码有点长是因为我是举具体示例 实际上 这里只是ListInsert的应用

#include <stdio.h>
#define MAXSIZE 10 
typedef struct 
{
    int data[MAXSIZE];
    int length;
}Sqlist;
void Initlist(Sqlist *L)
{
    L->length=5;
    for(int i=0;i<5;i++)
    {
        L->data[i]=i+2;
    }
    for(int j=5;j<10;j++)
    {
        L->data[j]=0;
    }
}
int ListInsert(Sqlist *L,int i,int e)
{
    /*这里的判断条件是异常情况
      L->length==0 线性表长度为0
      L->length==MAXSIZE 线性表的长度等于数组的长度饱和了无法插入
      i>L->length+1 插入的位置在数组内,但是大于线性表的长度*/
    if(L->length==0 || L->length==MAXSIZE || i<1 || i>L->length+1)
    {
        return 0;
    }
    /*如果插入的位置不在表尾 我们需要将i后的每一个元素都往后移动一位 将i位置空出来给新元素*/
    if(i<=L->length)
    {
        //这里的判断循环条件大家注意一下 j>=i-1 因为我们需要将i位置在数组下标就是i-1的位置空出来
        //所以包括i-1的位置也需要往后移动 这里判断才有=号
        for(int j=L->length;j>=i-1;j--)
        {
            L->data[j+1]=L->data[j];//每个元素往后移动一位,并不会影响到未移动的元素
        }
    }
    L->data[i-1]=e;//i-1的数组位置已经空出来了直接插入就可以
    L->length++;//因为加入了新元素 表长加一
    return 1;//代表插入成功
}
int main()
{
    Sqlist L;
    Initlist(&L);
    for(int i=0;i<5;i++)
     {
        printf("L.data[i]:%d\n",L.data[i]);
     }
    int e=66;
     printf("插入后\n");
    if(ListInsert(&L,2,e))//如果插入成功,输出插入后的线性表的元素
    {
        for(int i=0;i<L.length;i++)
        {
         printf("L.data[i]:%d\n",L.data[i]);
        }
    }
    else
    {
        printf("插入错误\n");
    }
    return 0;
}

2.5.6删除操作

删除算法的思路:如果删除的位置不合理 报错

                          :取出删除元素

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

                          :表长减一

#include <stdio.h>
#define MAXSIZE 10 
typedef struct 
{
    int data[MAXSIZE];
    int length;
}Sqlist;
void Initlist(Sqlist *L)
{
    L->length=5;
    for(int i=0;i<5;i++)
    {
        L->data[i]=i+2;
    }
} 
//删除 函数的参数是线性表地址和删除的位置i
int Listdelete(Sqlist *L,int i)
{
    if(L->length==0 || i<1 || i>L->length+1)//异常情况 前面都有详细描述 
    {
        return 0;
    }

    if(i<L->length)//如果不是尾元素
    {
       for(int j=i-1;j<=L->length;j++)//将i之后的元素全部往前移动一位 
         {
            L->data[j]=L->data[j+1];
         }
    }
    L->length--;// 表长减一
    return 1;
}
int main()
{
    Sqlist L;
    Initlist(&L);
    for(int i=0;i<5;i++)
     {
        printf("L.data[i]:%d\n",L.data[i]);
     }
    printf("删除之后的线性表\n");
    if(Listdelete(&L,2))
    {
        for(int i=0;i<L.length;i++)
      {
        printf("L.data[i]:%d\n",L.data[i]);
      }
    }
    return 0;
}

说到这里我们来总结一下线性表的顺序存储结构的优缺点

优点:无须为表示表中元素之间的逻辑关系而增加额外的存储空间

        :可以快速地存取表中任一位置的元素

缺点:插入和删除操作需要移动大量元素

       :当线性表长度变化较大时,难以确定存储空间的容量

       :造成存储空间的碎片

2.6线性表的链式存储结构

2.6.1概述

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

前面我们说线性表的特点的时候说过线性表应该是有序的 但这里为什么是任意的呢?

因为在链式结构中,除了要存数据元素信息外,还要存储它的后继元素的存储地址

因此:为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或链。这俩部分信息组成数据元素ai的存储映像,称为结点

其实简单的来说,链式存储有俩个部分组成,一个是数据域 一个是指针域 因为地址可以是任意的,所以通过指针来将线性表中的结点去连接起来。

这里我们介绍几个特殊的地方:对于线性表来说,有头有尾,链表也一样。我们把链表中第一个结点的存储位置叫做头指针,整个链表的存取必须是从头指针开始进行的,之后的每一个结点,其实是上一个的后继指针指向的位置 ,其中最后一个结点的指针指向空

我们有时会在单链表的第一个结点前,设一个结点,称为头结点,头结点的数据域不存储任何信息

头结点的指针域指向第一个结点的指针

我们来看一下头节点和头指针的异同

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

           :头指针具标识作用,所以常用头指针冠以链表的名字

          :无论链表是否为空,头指针均不为空,头指针是链表的必要元素

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

          :有了头结点,对于第一元素结点前插入和删除第一结点,其操作与其他结点的操作就统一了

           :头结点不一定是链表的必须要素

2.6.2 单链表的建立

这里我们来看一下c语言的实现先来看结构体

typedef struct node{
	int data;//数据域
	struct node *next;//指针域
}node, *LinkList;  //结构体的定义

再来看一下建立单链表,需要注意我们新建一个新结点就需要新开辟一次内存空间出来

为什么需要建立三个指针 一个是头指针,一个是用于新建结点,一个是用于存储上一次建立结点

通过存储上一次建立的结点 将上一次的结点与新建立的结点进行链接

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
	int data;
	struct node *next;
}node, *LinkList;  //结构体的定义

LinkList create_Link()
{  //创建单链表的主要代码(尾插法建立单链表)
	LinkList head = NULL;//建立一个头指针,用于指向第一个结点
	LinkList temp = NULL;
	LinkList tail = NULL;
    head=(LinkList)malloc(sizeof(node));//声明头指针的内存
    head->next=NULL;//将头指针指向空
    int x;//用于键入结点的数据域 也是用来判断循环结束的条件
    scanf("%d",&x);
    while(x!=0)//当建立足够的结点的时候 键入0 停止建立
    {
       temp=(LinkList)malloc(sizeof(node));//声明一块内存是用来存储新结点
       temp->next=NULL;//将新结点的指针指向空防止野指针
       temp->data=x;//新结点的数据域数据就是键入的值
       if(head->next==NULL)//当第一次插入的时候把头指针指向第一个结点
       {
         head->next=temp;
       }
       else//非第一次 ,将上一次的结点的指针域指向新结点
       {
         tail->next=temp;
       }
       tail=temp;//用于保存上一次建立的结点,用于中间值
       scanf("%d",&x);
    }
    tail->next=NULL;//将最后一个结点的指针域指向空
    return head;
}

int main(){  //主函数
	LinkList L = create_Link();
    L=L->next;
    while(L!=NULL)
    {
        printf("%d\n",L->data);
        L=L->next;
    }
	return 0;
}

 这里我们重新新建一个线性表将数据域元素改成赋值 而不是键入 方便我们后面其他操作 比如删除插入等,核心代码是不会变得

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
	int data;
	struct node *next;
}node, *LinkList;  //结构体的定义

LinkList create_Link()
{  //创建单链表的主要代码(尾插法建立单链表)
	LinkList head = NULL;//建立一个头指针,用于指向第一个结点
	LinkList temp = NULL;
	LinkList tail = NULL;
    head=(LinkList)malloc(sizeof(node));//声明头指针的内存
    head->next=NULL;//将头指针指向空
    for(int i=0;i<5;i++)
    {
       temp=(LinkList)malloc(sizeof(node));//声明一块内存是用来存储新结点
       temp->next=NULL;//将新结点的指针指向空防止野指针
       temp->data=i;//新结点的数据域数据就是键入的值
       if(head->next==NULL)//当第一次插入的时候把头指针指向第一个结点
       {
         head->next=temp;
       }
       else//非第一次 ,将上一次的结点的指针域指向新结点
       {
         tail->next=temp;
       }
       tail=temp;//用于保存上一次建立的结点,用于中间值

    }
    tail->next=NULL;//将最后一个结点的指针域指向空
    return head;
}

int main(){  //主函数
	LinkList L = create_Link();
    L=L->next;
    while(L!=NULL)
    {
        printf("%d\n",L->data);
        L=L->next;
    }
	return 0;
}

这里我们新建了一个单链表 有5个结点 数据域存放的分别是 0 1 2 3 4

后面我们对单链表的操作都是对这个表进行操作

 2.6.3单链表的读取

概述:获取第i个元素的数据域的值

思路:声明一个结点p指向链表的第一个结点,初始化j从1开始

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

       :若到链表未尾p为空,则说明第i个元素不存在

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

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
	int data;
	struct node *next;
}node, *LinkList;  //结构体的定义

LinkList create_Link()
{  //创建单链表的主要代码(尾插法建立单链表)
	LinkList head = NULL;//建立一个头指针,用于指向第一个结点
	LinkList temp = NULL;
	LinkList tail = NULL;
    head=(LinkList)malloc(sizeof(node));//声明头指针的内存
    head->next=NULL;//将头指针指向空
    for(int i=0;i<5;i++)
    {
       temp=(LinkList)malloc(sizeof(node));//声明一块内存是用来存储新结点
       temp->next=NULL;//将新结点的指针指向空防止野指针
       temp->data=i;//新结点的数据域数据就是键入的值
       if(head->next==NULL)//当第一次插入的时候把头指针指向第一个结点
       {
         head->next=temp;
       }
       else//非第一次 ,将上一次的结点的指针域指向新结点
       {
         tail->next=temp;
       }
       tail=temp;//用于保存上一次建立的结点,用于中间值

    }
    tail->next=NULL;//将最后一个结点的指针域指向空
    return head;
}
int Getlist(LinkList L,int i)
{
    //i=3
    int j=0;
    LinkList p;//声明一个结点p
    p=L->next;//p指向链表l的第一个结点
    while( p&& j<i)//当p不为空 和j《i的时候循环直到p为空 或者j》=i
    {
        p=p->next;
        ++j;
    }
    if(!p || j>i)//如果上述判断条件是p为空或者j>i的时候 即错误返回0
      return 0;

    return p->data;//返回第i个元素的数据域值
}
int main(){  //主函数
	LinkList L = create_Link();
    printf("%d\n",Getlist(L,3));
	return 0;
}

2.6.4单链表的插入

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
	int data;
	struct node *next;
}node, *LinkList;  //结构体的定义

LinkList create_Link()
{  //创建单链表的主要代码(尾插法建立单链表)
	LinkList head = NULL;//建立一个头指针,用于指向第一个结点
	LinkList temp = NULL;
	LinkList tail = NULL;
    head=(LinkList)malloc(sizeof(node));//声明头指针的内存
    head->next=NULL;//将头指针指向空
    for(int i=0;i<5;i++)
    {
       temp=(LinkList)malloc(sizeof(node));//声明一块内存是用来存储新结点
       temp->next=NULL;//将新结点的指针指向空防止野指针
       temp->data=i;//新结点的数据域数据就是键入的值
       if(head->next==NULL)//当第一次插入的时候把头指针指向第一个结点
       {
         head->next=temp;
       }
       else//非第一次 ,将上一次的结点的指针域指向新结点
       {
         tail->next=temp;
       }
       tail=temp;//用于保存上一次建立的结点,用于中间值

    }
    tail->next=NULL;//将最后一个结点的指针域指向空
    return head;
}
int  listinsert(LinkList L,int i,int e)
{
    LinkList p,new;
    p=L;
    int j=1;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p || j>i)
    return 0;//第i个元素不存在
    new=(LinkList)malloc(sizeof(node));//建立一块新的内存 存放结点
    new->data=e;//数据域赋值
    new->next=p->next;//将新结点的指针指向插入位置的下一个结点
    p->next=new;//将插入位置的上一个结点的指针域指向新结点
    return  1;
}
int main(){  //主函数
	LinkList L = create_Link();
    int a=listinsert(L,2,9);
    if(a)
    {
        L=L->next;
        while(L!=NULL)
        {
          printf("%d\n",L->data);
           L=L->next;
        }
    }
	return 0;
}

成功将9插入在第二个位置,这俩句是核心,一定要先将新结点的指针指向插入位置的下一个结点

    new->next=p->next;//将新结点的指针指向插入位置的下一个结点
    p->next=new;//将插入位置的上一个结点的指针域指向新结点

 2.6.5单链表的删除

这里我们需要注意我们要删除某个结点的时候我们将指针指向删除结点的上一个结点

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
	int data;
	struct node *next;
}node, *LinkList;  //结构体的定义

LinkList create_Link()
{  //创建单链表的主要代码(尾插法建立单链表)
	LinkList head = NULL;//建立一个头指针,用于指向第一个结点
	LinkList temp = NULL;
	LinkList tail = NULL;
    head=(LinkList)malloc(sizeof(node));//声明头指针的内存
    head->next=NULL;//将头指针指向空
    for(int i=0;i<5;i++)
    {
       temp=(LinkList)malloc(sizeof(node));//声明一块内存是用来存储新结点
       temp->next=NULL;//将新结点的指针指向空防止野指针
       temp->data=i;//新结点的数据域数据就是键入的值
       if(head->next==NULL)//当第一次插入的时候把头指针指向第一个结点
       {
         head->next=temp;
       }
       else//非第一次 ,将上一次的结点的指针域指向新结点
       {
         tail->next=temp;
       }
       tail=temp;//用于保存上一次建立的结点,用于中间值

    }
    tail->next=NULL;//将最后一个结点的指针域指向空
    return head;
}
int  listdelete(LinkList L,int i)
{
    LinkList p,q;
    p=L;
    int j=1;
    while(p->next&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p || j>i)
    return 0;//第i个元素不存在
    q=p->next;//将要删除的结点赋值给q
    p->next=q->next;//将指向删除结点的指针指向删除结点的下一个结点
    free(q);//释放删除结点的内存空间
    return  1;
}
int main(){  //主函数
	LinkList L = create_Link();
    int a=listdelete(L,2);
    if(a)
    {
        L=L->next;
        while(L!=NULL)
        {
          printf("%d\n",L->data);
           L=L->next;
        }
    }
	return 0;
}

2.6.6链表的整表删除

将每个结点的内存空间都进行释放

int  listclear(LinkList L,int i)
{
    LinkList p,q;
    p=L->next;
    while(p)
    {
        q=p->next;
        free(p);
        p=q;
    }
    L->next=NULL;
    return  1;
}

最后我们将单链表和顺序链接做一下对比

存储分配方式:顺序存储结构用一段连续的存储单元依次存储线性表的数据元素 利用数组

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

空间性能:顺序存储结构需要预分配存储空间,分大了 浪费 分小了 易发生上溢

              :单链表不需要分配存储空间只要有就可以分配,元素个数也不受限制

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

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

相关文章

fast-planner代码解读【kino_replan_fsm.cpp】

概述 kino_replan_fsm.cpp订阅实时定位和目标点信息&#xff0c;每隔0.01s执行一次状态机&#xff0c;进行状态切换&#xff1b;每隔0.05s执行一次碰撞检测&#xff0c;按需进行重新规划。核心为执行变量exec_state_ 主要函数及作用 KinoReplanFSM::init 输入&#xff1a;句…

SD-WAN解决方案:企业异地组网挑战之视频会议

随着企业的发展&#xff0c;不少企业开始面临规模扩大、分公司组建、异地办公的需求。其中&#xff0c;远程视频会议作为企业异地管理和运营的重要组成部分&#xff0c;对网络稳定性和视频传输质量有较高的要求。在本文&#xff0c;我们将探讨企业视频会议遇到的网络问题以及这…

SpringBoot+Vue+MySQL:图书管理系统的技术革新

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

面试经典150题——生命游戏

​"Push yourself, because no one else is going to do it for you." - Unknown 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力求解 之所以先暴力求解&#xff0c;是因为我开始也没什么更好的思路&#xff0c;所以就先写一种解决方案&#xff0c;没准写着写…

2月21日

Bean生命周期 过程概述 创建对象 实例化(构造方法) 依赖注入 初始化 执行Aware接口回调 执行BeanPostProcessor.psotProcessBeforeInitialization 执行InitializingBean回调(先执行PostConstruct) 执行BeanPsotProcessor.postProcessAfterInitialization 使用对象 销毁对象…

Javaweb之SpringBootWeb案例之切入点表达式的详细解析

3.3 切入点表达式 从AOP的入门程序到现在&#xff0c;我们一直都在使用切入点表达式来描述切入点。下面我们就来详细的介绍一下切入点表达式的具体写法。 切入点表达式&#xff1a; 描述切入点方法的一种表达式 作用&#xff1a;主要用来决定项目中的哪些方法需要加入通知 …

ffmpeg TS复用代码详解——mpegtsenc.c

一、mpegtsenc.c 整体架构 二、主要函数 mpegts_write_pes(AVFormatContext *s, AVStream *st, const uint8_t *payload, int payload_size, int64_t pts, int64_t dts)这个函数就是TS打包的主函数了&#xff0c;这个函数主要功能就是把一帧数据拆分成188字节的TS包&#xff0…

自助点餐系统微信小程序,支持外卖、到店等

总体介绍 系统总共分为三个端&#xff1a;后端&#xff0c;后台管理系统、微信小程序。 基于当前流行技术组合的前后端分离商城系统&#xff1a; SpringBoot2MybatisPlusSpringSecurityjwtredisVue的前后端分离的商城系统&#xff0c; 包含分类、sku、积分、多门店等 预览图…

FariyGUI × Cocos Creator 入门

前言 程序员向的初探Cocos Creator结和FairyGUI的使用&#xff0c;会比较偏向FairyGUI一点&#xff0c;默认各位读者都熟练掌握Cocos Creator以及js/ts脚本编写。 初探门径&#xff0c;欢迎大佬指教&#xff0c;欢迎在评论区或私信与本人交流&#xff0c;谢谢&#xff01; 下…

DBSCAN密度聚类介绍 样本点 样本集合 半径 邻域 核心对象 边界点 密度直达 密度可达 密度相连

DBSCAN密度聚类介绍 样本点 样本集合 半径 邻域 核心对象 边界点 密度直达 密度可达 密度相连 简介概念定义原理DBSCAN的优点DBSCAN的缺点小尝试制作不易&#xff0c;感谢三连&#xff0c;谢谢啦 简介 DBSCAN&#xff08;Density-Based Spatial Clustering of Applications wi…

Codeforces Round 927 (Div. 3)(A,B,C,D,E,F,G)

这场简单些&#xff0c;E题是个推结论的数学题&#xff0c;沾点高精的思想。F是个需要些预处理的DP&#xff0c;G题是用exgcd算边权的堆优化dijkstra。C题有点骗&#xff0c;硬啃很难做。 A Thorns and Coins 题意&#xff1a; 在你的电脑宇宙之旅中&#xff0c;你偶然发现了…

LeetCode 0105.从前序与中序遍历序列构造二叉树:分治(递归)——五彩斑斓的题解(若不是彩色的可以点击原文链接查看)

【LetMeFly】105.从前序与中序遍历序列构造二叉树&#xff1a;分治&#xff08;递归&#xff09;——五彩斑斓的题解&#xff08;若不是彩色的可以点击原文链接查看&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-preorder-a…

java数据类型、运算符

一、数据的表示详解 1.1 整数在计算机中的存储原理 任何数据在计算机中都是以二进制表示的。那这里肯定有人问&#xff0c;什么是二进制啊&#xff1f;所谓二进制其实就是一种数据的表示形式&#xff0c;它的特点是逢2进1。 数据的表示形式除了二进制&#xff08;逢2进1&…

Https证书续签-acme.sh-腾讯云之DnsPod

ename 域名切换到 DnsPod 上面解析 可以先看下之前的 acme.sh 介绍文章然后再来次补充更多。 之前说过了 acme.sh 在阿里云下的使用。 这里做个后续补充 之前的域名是在 ename 上的 &#xff0c;为了自动续签切换到 DnsPod 上面解析 注意事项 可以把原来 ename 上的解析先导出…

Android全新UI框架之Jetpack Compose入门基础

Jetpack Compose是什么 如果有跨端开发经验的同学&#xff0c;理解和学习compose可能没有那么大的压力。简单地说&#xff0c;compose可以让Android的原生开发也可以使用类似rn的jsx的语法来开发UI界面。以往&#xff0c;我们开发Android原生页面的时候&#xff0c;通常是在xml…

【八股文面试】Java基础常见面试题总结(上)

Java基础常见面试题总结(上) Java有哪些特性 简单易学&#xff1b;面向对象&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;&#xff1b;平台无关性&#xff08; Java 虚拟机实现平台无关性&#xff09;&#xff1b;支持多线程&#xff08; C 语言没有内置的多…

Springcloud:LiteFlow

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、LiteFlow简介 二、规则编排关键字及语法 1、THEN&#xff1a; 2、WHEN&#xff1a; 3、AND&#xff1a; 4、OR&#xff1a; 5、IF&#xff1a; 6、ELSE&…

手动代码实现神经网络

网络结构 第一层有13个神经元&#xff0c;第二层8个神经元&#xff0c;第三层是输出层&#xff1b;其中第一层的激活函数是relu&#xff0c;第二层是sigmoid 代码实现 # 导入库 import torch import torch.nn as nn from torch.nn import functional as F # 确定数据 torch…

使用IntelliJ IDEA查看接口的全部实现方法

在大型Java项目中&#xff0c;经常会使用接口和抽象类进行代码设计。为了更好地了解代码结构和功能&#xff0c;我们需要快速查看一个接口的所有实现类。IntelliJ IDEA提供了一些方便的方法来实现这一目标。 1. 点击查看接口的实现子类 在IDEA中&#xff0c;你可以轻松地查看…