基础知识学习---链表基础

news2024/12/24 21:08:25

1、本栏用来记录社招找工作过程中的内容,包括基础知识学习以及面试问题的记录等,以便于后续个人回顾学习; 暂时只有2023年3月份,第一次社招找工作的过程;

2、个人经历: 研究生期间课题是SLAM在无人机上的应用,有接触SLAM、Linux、ROS、C/C++、DJI OSDK等;
3、参加工作后(2021-2023年)岗位是嵌入式软件开发,主要是服务器开发,Linux、C/C++、网络编程、docker容器、CMake、makefile、Shell脚本、JSON等。

4、求职岗位是嵌入式软件开发、C/C++开发、自动驾驶岗位开发等。

在这里插入图片描述

文章目录

  • 一、单链表
    • 1.1 单链表基础
    • 1.2 创建一个无头节点的单链表
    • 1.3 创建一个有头节点的单链表
    • 1.4 单链表的增删改查操作
  • 二、双向链表
    • 2.1 双链表基础
    • 2.2 双链表的创建和初始化
    • 2.3 双向链表的增删改查

一、单链表

参考:
http://c.biancheng.net/view/3336.html

过程记录

1.1 单链表基础

一个完整的链表需要由以下几部分构成:
1、头指针:一个普通的指针,它的特点是永远指向链表第一个节点的位置。很明显,头指针用于指明链表的位置,便于后期找到链表并使用表中的数据;
2、节点:链表中的节点又细分为头节点首元节点其他节点
头节点:其实就是一个不存任何数据的空节点,通常作为链表的第一个节点。对于链表来说,头节点不是必须的,它的作用只是为了方便解决某些实际问题;
首元节点:由于头节点(也就是空节点)的缘故,链表中称第一个存有数据的节点为首元节点。首元节点只是对链表中第一个存有数据节点的一个称谓,没有实际意义;
其他节点:链表中其他的节点;

因此,一个存储 {1,2,3} 的完整链表结构如下图 所示:
在这里插入图片描述
注意:链表中有头节点时,头指针指向头节点;反之,若链表中没有头节点,则头指针指向首元节点。

1.2 创建一个无头节点的单链表

无头节点的链表创建成功后的最终结果如下图所示:
在这里插入图片描述
创建一个存储 {1,2,3,4} 且无头节点的链表,C 语言实现代码如下:

#include<stdio.h>
#include<malloc.h>

typedef struct Link
{
    int data;//数据域,存放数据信息
    struct Link * Next;//指针域,用于指向后继元素
}link;//link为节点名,每一个节点都是一个link结构体

link * initlink();//初始化链表
void print(link * InputLink);//遍历链表并打印里面的data数据

int main()
{
    link * p = initlink();//建立一个链表p,并调用initLink进行初始化
    print(p);//遍历并打印该链表的data

    return 0;
}

/*创建一个存储 {1,2,3,4} 且无头节点的链表,并初始化*/
link * initlink()
{
    link * p = NULL;//先创建一个空的头指针
    
    /*创建首元节点*/
    link *tmp = NULL;
    tmp = (link *)malloc(sizeof(link));
    tmp->data = 1;//首元节点的数据赋值为1
    tmp->Next = NULL;

    p = tmp;//头指针指向首元节点

    /*循环创建3个数据节点*/
    int i;
    for(i = 2; i<5; i++)
    {
        
        link * a = NULL;
        a = (link*)malloc(sizeof(link));
        a->data = i;//节点中的数据设置为i值,即2,3,4
        a->Next = NULL;
   
       tmp->Next = a;//将temp节点与新建立的a节点建立逻辑关系,即前一个的next指向后面的节点

        //第一次循环,将tmp节点由指向首元节点改为指向第一个a节点;剩下的循环,将tmp由指向旧的a改为指向新的a
        //即指针temp每次都指向新链表的最后一个节点,其实就是 a节点,这里写temp=a也对
        
        tmp = tmp->Next;
    }
   

    return p;
}

void print(link * InputLink)
{
    link *tmp = InputLink;//建立一个临时的指针,用来遍历链表,刚开始先指向链表的头指针
    while(NULL!=tmp)//如果tmp不为空,说明有该节点,即可取数据。
    {
        printf("%d ",tmp->data);//打印该节点中的数据
        tmp = tmp->Next;//tmp指向该节点中的Next指针,当遍历到最后一个节点时,该最后节点的Next指针为空,此时tmp也为空,则下一个循环就不会进入了
    }
}

运行结果:
在这里插入图片描述

1.3 创建一个有头节点的单链表

有头节点的链表创建成功后的最终结果如下图所示:
在这里插入图片描述

创建一个存储 {1,2,3,4} 且有头节点的链表,C 语言实现代码如下:


#include<stdio.h>
#include<malloc.h>

typedef struct Link
{
    int data;//数据域,存放数据信息
    struct Link * Next;//指针域,用于指向后继元素
}link;//link为节点名,每一个节点都是一个link结构体

link * initlink();//初始化链表
void print(link * InputLink);//遍历链表并打印里面的data数据

int main()
{
    link * p = initlink();//建立一个链表p,并调用initLink进行初始化
    print(p);

    return 0;
}

/*创建一个存储 {1,2,3,4} 且有头节点的链表,并初始化*/
link * initlink()
{
    link * p = (link *)malloc(sizeof(link));//创建头结点
    link *tmp = p;
    int i ;
    for(i = 1;i<5;i++)
    {
        link * a = (link *)malloc(sizeof(link));
        a->data = i;
        a->Next = NULL;

        tmp ->Next = a;
        tmp = tmp->Next;
    }

    return p;
}

/*使用带有头节点创建链表的方式,则print函数总打印链表中的数据时,要跳过头结点,因为头结点中是没有数据的,所以判断条件为“当下一个节点中的Next不为NULL时,即说明它不是最后一个节点,就打印此” */
void print(link * InputLink)
{
    link *tmp = InputLink;//建立一个临时的指针,用来遍历链表,刚开始先指向链表的头指针
    while(NULL!=tmp->Next)//判断tmp->Next是否为空,不为空说明后面有节点,即不是最后一个节点;为什么不判断tmp?因为tmp第一次代表头结点,头结点的data没数据。
    {
        printf("%d ",tmp->Next->data);//打印tmp节点下一个中的数据,即跳过了第一个节点也就是头结点
        tmp = tmp->Next;//指向下一个节点
    }
}


运行结果:
在这里插入图片描述

1.4 单链表的增删改查操作

在写增删改查函数时,一定要时刻参照单链表的图,如下:

在这里插入图片描述

增删改查总代码:

#include<stdio.h>
#include<malloc.h>

typedef struct Link
{
    int data;//数据域,存放数据信息
    struct Link * Next;//指针域,用于指向后继元素
}link;//link为节点名,每一个节点都是一个link结构体

link * initlink();//初始化链表
void print(link * InputLink);//遍历链表并打印里面的data数据
link * Insert(link * TargetLink,int data_new,int Add);//向链表中插入元素
link * Delate(link *TargetLink,int pos_del);//删除链表中的指定节点
link* deleteNode(link* head, int val);//删除指定元素
link * update(link *TargetLink ,int date_new,int pos_update);//修改链表中的元素
int select(link *TargetLink,int date_select);//在链表中查找元素

int main()
{
    link * p = initlink();//建立一个链表p,并调用initLink进行初始化
    printf("原链表:");
    print(p);
    printf("\n");

    link * Add = Insert(p,5,2);//调用插入函数,向原链表中第二个节点插入一个数字5
    printf("插入元素后的链表:");
    print(p);
    printf("\n"); 

    link * Del = Delate(p,2);//调用删除函数,删除第二个节点   
    printf("删除第2个节点后的链表:");
    print(p);
    printf("\n"); 


    link * Del_ = deleteNode(p,2);//调用删除函数,删除数据为2的节点   
    printf("删除数字为2的节点后的链表:");
    print(p);
    printf("\n"); 


    link * up = update(p,5,2);//调用修改函数,将原链表第二个位置的数字修改为5
    printf("修改元素后的链表:");
    print(p);
    printf("\n");

    int pos_sec =  select(p,5);//调用查找函数,在链表中查找数字5对应的节点位置
    printf("数字5是第%d个节点\n",pos_sec);

    return 0;
}

#if 1
/*创建一个存储 {1,2,3,4} 且有头节点的链表,并初始化*/
link * initlink()
{
    link * p = (link *)malloc(sizeof(link));//创建头结点
    link *tmp = p;
    int i ;
    for(i = 1;i<5;i++)
    {
        link * a = (link *)malloc(sizeof(link));
        a->data = i;
        a->Next = NULL;

        tmp ->Next = a;
        tmp = tmp->Next;
    }

    return p;
}

/*使用带有头节点创建链表的方式,则print函数总打印链表中的数据时,要跳过头结点,因为头结点中是没有数据的,所以判断条件为“当下一个节点中的Next不为NULL时,即说明它不是最后一个节点,就打印此” */
void print(link * InputLink)
{
    link *tmp = InputLink;//建立一个临时的指针,用来遍历链表,刚开始先指向链表的头指针
    while(NULL!=tmp->Next)//判断tmp->Next是否为空,不为空说明后面有节点,即不是最后一个节点;为什么不判断tmp?因为tmp第一次代表头结点,头结点的data没数据。
    {
        printf("%d ",tmp->Next->data);//打印tmp节点下一个中的数据,即跳过了第一个节点也就是头结点
        tmp = tmp->Next;//指向下一个节点
    }
}


/*
功能:向链表中插入元素
入参:
link *TargetLink 要插入数据的目标链表(带有头结点)
int data_new  要插入的元素数据
int Add   要插入的位置,比如Add为2,则将新元素插在节点2的位置上

*/
link * Insert(link * TargetLink,int data_new,int Add)
{
    link *tmp = TargetLink;
    int i ;
    for(i = 1;i<Add;i++)//因为有头结点的存在,所以不必单独判断是否是插入在首元节点之前还是之后,整个步骤都是一样的,因为都是插入在头结点之后的。不用单独判断Add是否为1
    {
        if(NULL == tmp->Next)//说明没找到符合Add位置的节点,即超出了原链表的范围
        {
            printf("error:Add Not in Link\n");
            return TargetLink;
        }
        tmp = tmp->Next;
    }
    //创建新节点
    link * New = (link *)malloc(sizeof(link));
    New ->data = data_new;
    //向链表中插入节点
    New->Next = tmp->Next;
    tmp->Next = New;
    return TargetLink;
}


/*
功能:向链表中删除元素
入参:
link *TargetLink 要删除数据的目标链表(带有头结点)
int pos_del  要删除的节点位置
*/
link * Delate(link *TargetLink,int pos_del)
{
    link *tmp = TargetLink;
    int i ;
    for(i = 1;i<pos_del;i++)
    {
        if(NULL == tmp->Next)//说明没找到符合删除位置的节点,即超出了原链表的范围
        {
            printf("error:没有该节点\n");
            return TargetLink;
        }
        tmp = tmp->Next;//此时的tmp已经指向了要删除的节点的前面的节点
    }  
    //单独设置一个指针,指向要删除的节点,用于释放该节点
    link * del = tmp->Next;//因为此时tmp指向的是要删除节点的前面的节点,因此被删除节点时tmp->Next
    tmp->Next = tmp->Next->Next;//tmp里的Next指针指向下一个节点里的Next指针
    free(del);//手动释放该节点,防止内存泄漏
    return TargetLink;
}


/*
功能:向链表中删除元素
入参:
link *head 要删除数据的目标链表(不带头结点)
int val  要删除的数据
*/
link* deleteNode(link* head, int val) {
	int pos = 1;//用于要删除的是第几个节点
	link *tmp1 = head;//用于指向被删除的节点
	link *tmp2 = head;//用于指向被删除节点的前一个节点
	while(NULL != tmp1 )
	{

		if(val == tmp1 -> data)//如果是要删除的数据
		{
			if(1 == pos)//如果是第一个节点
			{
				head = tmp1 -> Next;//需要将头指针指向后一个节点,因为第一个要被删除
			}
			else//如果被删除的不是头结点
			{
				tmp2 -> Next = tmp1 -> Next;//被删除节点的前一个节点的Next指向被删除节点的后一个节点
				tmp1 -> Next = NULL;//被删除的节点的Next指向空
				free(tmp1);//释放掉要被删除的节点
			}					
			return head;
			
		}
		else//如果不是要删除的数据,则记录继续往下遍历
		{
			tmp2 = tmp1;//此处:tmp2记录下tmp1的前一个节点
			tmp1 = tmp1 -> Next;//tmp1继续往下
			pos ++;//记录被删除的是第几个节点
		}
	}
	return head;
}

/*
功能:链表中修改元素
入参:
link *TargetLink 要修改数据的目标链表(带有头结点)
int date_new    要修改成的数据
int pos_update  要修改的节点位置
*/
link * update(link *TargetLink ,int date_new,int pos_update)
{
    link *tmp = TargetLink;
    int i ;
    for(i = 0;i<pos_update;i++)
    {
        if(NULL == tmp->Next)//说明没找到符合修改位置的节点,即超出了原链表的范围
        {
            printf("error:没有该节点\n");
            return TargetLink;
        }
        tmp = tmp->Next;//此时的tmp已经指向了要修改的节点
    }  
    tmp->data = date_new;  
    return TargetLink; 
}


/*
功能:在链表中查找目标元素,返回找到的位置,未找到返回-1
入参:
link *TargetLink 要查找数据的目标链表(带有头结点)
int date_select  要查找到数据
*/
int select(link *TargetLink,int date_select)
{
    link *tmp = TargetLink;
    int i = 1;//从首元节点开始,第一次循环即首元节点的位置
    while(NULL != tmp->Next)//因为有头结点,头结点没数据,所以需要跳过头结点,直接找首元节点的数据;所以头指针的Next为首元节点,即跳过头结点
    {
        if(date_select == tmp->Next->data)
        {
            return i;//找到了,返回i
        }
        tmp = tmp->Next;
        i++;
    }
    return -1;
    
}

#endif

执行结果:
在这里插入图片描述

二、双向链表

2.1 双链表基础

从名字上理解双向链表,即链表是 “双向” 的,如图 1 所示:
在这里插入图片描述

双向,指的是各节点之间的逻辑关系是双向的,但通常头指针只设置一个,除非实际情况需要

从图 1 中可以看到,双向链表中各节点包含以下 3 部分信息(如图 2 所示):
指针域:用于指向当前节点的直接前驱节点;
数据域:用于存储数据元素。
指针域:用于指向当前节点的直接后继节点;
在这里插入图片描述
因此,双链表的节点结构用 C 语言实现为:

typedef struct line{
    struct line * prior; //指向直接前趋
    int data;
    struct line * next; //指向直接后继
}line;

2.2 双链表的创建和初始化

同单链表相比,双链表仅是各节点多了一个用于指向直接前驱的指针域。因此,我们可以在单链表的基础轻松实现对双链表的创建。

需要注意的是,与单链表不同,双链表创建过程中,每创建一个新节点,都要与其前驱节点建立两次联系,分别是:

  • 将新节点的 prior 指针指向直接前驱节点;
  • 将直接前驱节点的 next 指针指向新节点;

创建好后的链表如下图所示:
在这里插入图片描述

具体代码实现:

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

typedef struct Line
{ 
    struct Line * prior;//指向直接前驱
    int  data;
    struct Line * next;//指向直接后继
}line;

line * lineInit();//双链表初始化函数
int print(line * TargetLine);//遍历打印双链表里的数据

line * lineInit()
{
    line *head = NULL;//定义一个双链表的头指针

    line * tmp = (line *)malloc(sizeof(line));//创建第一个节点(首元节点)并分配内存
    tmp->prior = NULL;
    tmp->data = 1;
    tmp->next = NULL;

    head = tmp;//头指针指向第一个节点

    int i;
    for(i = 2;i<4;i++)
    {
        line * body = (line *)malloc(sizeof(line));//创建后续的节点
        body ->prior=tmp;//前驱指针指向前面的节点
        body ->data = i;
        body ->next = NULL;//后继指针指向空
        tmp ->next = body;//前面节点的后继指针指向当前节点
        
        tmp = tmp->next;//tmp永远指向当前最后一个节点
    }
    return head;
    
}

int print(line * TargetLine)
{
    line * tmp = TargetLine;//新建tmp指针指向双链表头指针,用来遍历双链表
    while(NULL != tmp )
    {
        if(NULL == tmp -> next)
            printf("%d",tmp->data);
        else
            printf("%d <-> ",tmp->data);
        tmp = tmp ->next;//tmp指向后面的节点
    }
    return 0;
}

int main()
{
    line * source = lineInit();
    printf("初始化的链表为:");
    print(source);
    printf("\n");
    return 0;
}

运行结果:
在这里插入图片描述

2.3 双向链表的增删改查

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

typedef struct Line
{ 
    struct Line * prior;//指向直接前驱
    int  data;
    struct Line * next;//指向直接后继
}line;

line * lineInit();//双链表初始化函数
int print(line * TargetLine);//遍历打印双链表里的数据
line * Insert(line *Targetline, int date_new, int Add);//向链表中插入元素
line * Delate(line *TargetLine,int pos_del);//向链表中删除元素
line * update(line *TargetLine ,int date_new,int pos_update);//修改链表中的元素
int select_double(line *TargetLine,int date_select);//在链表中查找元素

line * lineInit()
{
    line *head = NULL;//定义一个双链表的头指针

    line * tmp = (line *)malloc(sizeof(line));//创建第一个节点(首元节点)并分配内存
    tmp->prior = NULL;
    tmp->data = 1;
    tmp->next = NULL;

    head = tmp;//头指针指向第一个节点

    int i;
    for(i = 2;i<4;i++)
    {
        line * body = (line *)malloc(sizeof(line));//创建后续的节点
        body ->prior=tmp;//前驱指针指向前面的节点
        body ->data = i;
        body ->next = NULL;//后继指针指向空
        tmp ->next = body;//前面节点的后继指针指向当前节点
        
        tmp = tmp->next;//tmp永远指向当前最后一个节点
    }
    return head;
    
}

int print(line * TargetLine)
{
    line * tmp = TargetLine;//新建tmp指针指向双链表头指针,用来遍历双链表
    while(NULL != tmp )
    {
        if(NULL == tmp -> next)
            printf("%d",tmp->data);
        else
            printf("%d <-> ",tmp->data);
        tmp = tmp ->next;//tmp指向后面的节点
    }
    return 0;
}

/*
功能:向链表中插入元素
入参:
line *Targetline 要插入数据的目标链表(带有头结点)
int data_new  要插入的元素数据
int Add   要插入的位置,比如Add为2,则将新元素插在节点2的位置上
*/

line * Insert(line *Targetline, int date_new, int Add)
{
    //printf("Insert\n");
    line * tmp = Targetline;//定义临时指针,刚开始指向双链表头指针,后面用来遍历整个链表

    /*先判断Add是否在双链表的位置中*/
    int i;
    for(i = 1;i<Add-1;i++)//为什么是Add-1呢?因为目的是找到要插入位置的前一个结点
    {
        if(NULL == tmp)
        {
            printf("ERROR:Add Not exist");
            return Targetline;
        }
        tmp = tmp->next;
        //printf("i is %d\n",i);
    }
    //经过for循环出来后,此时tmp指向的节点就是咱们要插入的位置的前一个节点
    if(1 == Add)//如果是插在第一个节点的位置,需要单独处理,因为要改变头指针,头指针改为指向新建的节点,此时没进上面的for循环,tmp还是指向头节点的
    {
        line * New_head = (line *)malloc(sizeof(line));
        New_head ->prior = NULL;//新的头结点前驱指针指向NULL
        New_head->data = date_new;
        New_head->next =tmp;//新的头结点的后继指针指向旧的头结点
        tmp->prior= New_head;//旧的头结点的前驱指针指向新的头结点

        Targetline = New_head;//头指针指向新的头结点
    }
    else//如果不是插在第一个节点的位置
    {
        if(NULL == tmp->next)//说明tmp是最后一个节点了,即需要查到最后一个节点后面
        {
            line * body_final = (line *)malloc(sizeof(line));
            body_final ->prior = tmp;//新的结点前驱指针指向插入位置的前一个节点
            body_final->data = date_new;
            body_final->next = NULL;//新的结点的后继指针指向空 

            tmp->next = body_final;//原来的最后一个节点的后继指针指向新建立的节点,此时原来的最后一个节点变成了倒数第二个节点,新建立的节点变成了最后一个节点
        }
        else//此时说明是插入到中间位置
        {
            line * body_new = (line *)malloc(sizeof(line));
            body_new ->prior = tmp;//新的结点前驱指针指向原节点的前驱节点
            body_new->data = date_new;
            body_new->next =tmp->next;//新的结点的后继指针指向原结点

            tmp ->next ->prior = body_new;//原节点的前驱指针指向新节点
            tmp ->next = body_new;//旧节点的前一个节点的后继指针指向新节点
            
        }

    }

    return Targetline;
}

/*
功能:向双链表中删除元素
入参:
line *TargetLine 要删除数据的目标链表
int pos_del  要删除的节点位置
*/
line * Delate(line *TargetLine,int pos_del)
{
    line *tmp = TargetLine;
    int i;
    for(i = 1;i<pos_del;i++)
    {
        if(NULL == tmp ->next)
        {
            printf("ERROR:pos_del Not exit");
            return TargetLine;
        }
        tmp = tmp ->next;//此时tmp指向了要删除的节点
    }
    if(1 == pos_del)//如果要删除的是头结点
    {
        tmp ->next->prior = NULL;//原头结点的下一个节点的前驱指针指向空
        TargetLine = tmp->next;//头指针指向原头结点的下一个节点

        tmp ->next = NULL;//原头结点的后驱指针指向空

        line * Del = tmp;//新建一个指针指向要删除的节点,用于释放内存
        free(Del);

    }
    else if(NULL == tmp ->next)//tmp->next为空说明要删除的是尾节点
    {        
        tmp ->prior->next = NULL;//要删除节点的前一个节点的后驱指针指向空
        tmp ->prior = NULL;
        free(tmp);
    }
    else//要删除的既不是头结点,也不是尾节点
    {
        tmp ->prior->next = tmp ->next;//要删除节点的前一个节点的后驱指针指向要删除节点的下一个节点
        tmp ->next->prior = tmp ->prior;//要删除节点的后一个节点的前驱指针指向要删除节点的前一个节点

        tmp ->prior =NULL;
        tmp ->next = NULL;
        free(tmp);
    }

    return TargetLine;
}

/*
功能:链表中修改元素
入参:
line *TargetLine 要修改数据的目标链表(带有头结点)
int date_new    要修改成的数据
int pos_update  要修改的节点位置
*/
line * update(line *TargetLine ,int date_new,int pos_update)
{
    line *tmp = TargetLine;
    int i ;
    for(i = 1;i<pos_update;i++)
    {
        if(NULL == tmp)//说明没找到符合修改位置的节点,即超出了原链表的范围
        {
            printf("error:没有该节点\n");
            return TargetLine;
        }
        tmp = tmp->next;//此时的tmp已经指向了要修改的节点
    }  
    tmp->data = date_new;  
    return TargetLine; 
}


/*
功能:在链表中查找目标元素,返回找到的位置,未找到返回-1
入参:
line *TargetLine 要查找数据的目标链表(带有头结点)
int date_select  要查找到数据
*/
int select_double(line *TargetLine,int date_select)
{
    line *tmp = TargetLine;
    int i = 1;//从首元节点开始,第一次循环即首元节点的位置
    while(NULL != tmp)
    {
        if(date_select == tmp->data)
        {
            return i;//找到了,返回i
        }
        tmp = tmp->next;
        i++;
    }
    return -1;
    
}


int main()
{
    line * source = lineInit();
    printf("初始化的链表为:");
    print(source);
    printf("\n");

    source = Insert(source,4,4);//将数字4插入到第三个节点
    printf("插入节点后的链表为:");
    print(source);
    printf("\n");

    source = Delate(source,4);//删除第4个节点
    printf("删除节点后的链表为:");
    print(source);    
    printf("\n");

    source = update(source,6,3);//修改第3个节点为6
    printf("修改节点后的链表为:");
    print(source);    
    printf("\n");    

    int pos_sec =  select_double(source,6);//调用查找函数,在链表中查找数字5对应的节点位置
    printf("数字6是第%d个节点\n",pos_sec);

    return 0;
}



执行结果:
在这里插入图片描述

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

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

相关文章

Vue中如何进行音频与视频播放?

Vue中如何进行音频与视频播放&#xff1f; 在Vue中&#xff0c;我们可以使用HTML5的<audio>和<video>标签来实现音频和视频的播放。Vue本身并没有提供专门的音频或视频播放组件&#xff0c;但是可以使用Vue的数据绑定和生命周期钩子来控制音频和视频的播放。 音频…

【gcc, cmake, eigen, opencv,ubuntu】一.gcc介绍

文章目录 gcc介绍1.查看当前gcc 版本2.安装其他版本的gcc3.设置多个版本的优先级4.修改默认的版本5.查看cpu信息 gcc介绍 gcc介绍和makefile介绍 1.查看当前gcc 版本 gcc --version2.安装其他版本的gcc sudo apt install gcc-10 g-10这样我们电脑里包含gcc-9 和 gcc-10两个…

[玩游戏想道理]战略的感受

game&#xff1a;金铲铲之战 战略的定义可以说是非常多了&#xff0c;这里主要是就游戏中的过程谈一些实践感受和理解&#xff1b; 这里也不是谈战略的定义xxxx&#xff0c;这方面的理论包括《孙子兵法》都是强太多了&#xff0c;主要就是在游戏这个“现实模拟器”中&#xff0…

全志V3S嵌入式驱动开发(开机脚本、程序运行)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 目前为止的内容&#xff0c;大部分都是和驱动相关的。就算有部分上层代码&#xff0c;也只是为了测试驱动是否ok而编写的。事实上&#xff0c;作为…

团队管理之性能实施团队日志13

项目经过了&#xff0c;8 个业务系统和 7 个基础架构系统的测试之后&#xff0c;又完成了全链路的两个域的测试&#xff0c;终于进入了尾声。 过程中发现了 257 个问题&#xff08;只统计了 8 个业务系统&#xff09;&#xff0c;平均每个系统 32.125 个。问题 age 达到 861.77…

「微服务架构模式」编曲与编舞——让系统协同工作的不同模式

介绍 Krzysztof&#xff08;采访者&#xff09;&#xff1a;商业组织是由专家组成的&#xff0c;他们在他们最了解的领域提供产品或服务&#xff0c;以获得共同的商业成果。例如&#xff0c;营销团队努力争取新客户&#xff0c;销售团队向这些客户销售产品&#xff0c;客户关系…

用4种回归方法绘制预测结果图表:向量回归、随机森林回归、线性回归、K-最近邻回归

文章目录 表格部分数据如下运行效果如下代码解析完整代码附件 表格部分数据如下 附件里会给出全部数据链接 运行效果如下 代码解析 import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib.font_manager import FontPropertiesfont FontP…

FPGA实现USB3.0 UVC 相机彩条视频输出 基于FT602驱动 提供工程源码和QT上位机源码

目录 1、前言2、UVC简介3、FT602芯片解读4、我这儿的 FT601 USB3.0通信方案5、详细设计方案基于FT602的UVC模块详解 6、vivado工程详解7、上板调试验证8、福利&#xff1a;工程代码的获取 1、前言 目前USB3.0的实现方案很多&#xff0c;但就简单好用的角度而言&#xff0c;FT6…

用代码玩转迷你图:手把手教你用编程语言打造简洁易读的数据图表!

前言 迷你图&#xff08;Mini Chart&#xff09;最早起源于流程图和组织架构图中的一种简化图形&#xff0c;用于表示一个大型数据集合中的趋势和变化。随着数据可视化技术的发展&#xff0c;迷你图也被广泛应用在各种类型的数据图表中&#xff0c;例如折线图、柱形图、散点图…

【027】C++类和对象的基本概念

C类和对象的基本概念 引言一、类的封装性二、定义一个类三、设计一个类3.1、示例一&#xff1a;设计一个Person类3.1、示例二&#xff1a;设计一个Cube类 四、成员函数在类外实现五、类在其他源文件中实现总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计…

RFID工业读头工作原理和优势

RFID工业读头由天线&#xff0c;耦合元件&#xff0c;芯片&#xff0c;可对RFID标签信息进行读取和写入&#xff0c;在工业上也常作为信息的传输、处理的载体。下面我们就一起来了解一下&#xff0c;工业读头工作原理和优势是什么。 工业读头工作原理 工业RFID读头主要是通过天…

微信小程序嵌入H5页面,最简单的兼容方式web-view

//index.wxml---------------------------------------- <web-view src"{{src}}" />//index.js---------------------------------------- Page({data: {src: "https://dz.wedoyun.cn/mobile/?v20230615",},});

1.6C++双目运算符重载

C双目运算符重载 C中的双目运算符重载指的是重载二元运算符&#xff0c;即有两个操作数的运算符&#xff0c;如加减乘除运算符“”、“-”、“*”和“/”等。 通过重载双目运算符&#xff0c;可以实现自定义类型的运算符操作。 比如可以通过重载加减运算符实现自定义类型的向…

电脑误删文件恢复怎么做?数据恢复,4招就行!

我有定期清理电脑的习惯&#xff0c;一般都会将电脑里的一些垃圾文件删除&#xff0c;但在最近一次的清理中&#xff0c;我不小心把重要的文件当作垃圾文件删除了&#xff0c;请问有什么比较好的解决方法吗&#xff1f;非常感谢&#xff01; 当下电脑的使用越来越频繁&#xff…

抖音seo源码-源代码开发搭建-开源部署(不加密)

抖音SEO矩阵系统源码开发功能模型是指在抖音平台上提高视频搜索排名的一种算法模型。该功能模型包括多个部分&#xff0c;如内容优化、用户交互、社交化推广等&#xff0c;通过对这些因素的优化和提升&#xff0c;达到提高视频搜索排名的目的。具体实现包括使用关键词、标签等优…

谷粒商城p46-配置网关路由与路径重写

软件 &#xff1a; vscode idea 服务&#xff1a; renren-fast&#xff0c;gulimall-product&#xff0c;gulimall-gateway、nacos 前提条件&#xff1a; gateway、renren-fast已经注册到nacos 注意&#xff1a; 1、renren-fast单独注入nacos依赖&#xff0c;不要注入common…

CAD绘制三维图形基础

绘制三维图形的基础操作包括&#xff1a; 1、打开3d绘图窗口&#xff0c;进入3d绘图界面 2、改变绘图视角 3、改变图形的展现形式 4、绘制基本的几何图形 5、掌握对齐等修改功能 6、掌握基础布尔操作 首先是切换工作空间&#xff0c;在界面的右下角有一个类似设置的按钮…

使用VitePress创建个人网站并部署到GitHub

网站在线预览 参考文档&#xff1a; VitePress 创建 GitHub 远程仓库 克隆远程仓库到本地 git clone gitgithub.com:themusecatcher/front-end-notes.git进入 front-end-notes/ 目录&#xff0c;添加 README.md 并建立分支跟踪 echo "# front-end-notes" >>…

配置Kettle连接大数据HDFS

需求&#xff1a;配置Kettle连接大数据HDFS Kettle对接大数据平台的配置 一&#xff0e;软件环境 1.Hadoop集群,版本&#xff1a;Hadoop3.3.0 2.ETL工具Kettle&#xff0c;版本&#xff1a;pdi-ce-7.0.0.0-25 &#xff08;解压命令&#xff1a;*.zip 用 unzip 解压&#xf…

4自由度并联机器狗实现下蹲功能

1. 功能说明 本文示例将实现R328a样机4自由度并联机器狗下蹲的功能。 2. 结构说明 本样机的并联驱动结构与 【R082】4自由度并联四足 类似&#xff0c;两款样机可以对比来看。 本样机腿部的结构如下图所示&#xff1a;驱动核心部分是两个5杆结构的组合。 两个五杆结构图 驱动核…