C语言——链表

大神文献:https://blog.csdn.net/weixin_73588765/article/details/128356985

目录

一、链表概念

1. 什么是链表?

1.1 链表的构成

2. 链表和数组的区别

数组的特点:

链表的特点:               

二者对比:

二、链表静态添加和遍历

三、统计链表节点个数、链表查询及修改节点

四、在指定节点插入新的节点

1.在指定节点后插入新的节点

2.在指定节点的前方插入新节点

1.第一个节点之前插入新的节点;

2.在中间的节点插入新的节点;

完整代码:

五、删除指定节点

1.删除第一个节点

2.删除中间的节点

完整代码:

六、动态创建节点 

头插法

尾插法


一、链表概念

1. 什么是链表?

链表是一种数据结构,是一种数据存放的思想;

链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。

1.1 链表的构成

构成:链表由一个个结点组成,每个结点包含两个部分:数据域 和 指针域。

  • 数据域(data field):每个结点中存储的数据。

  • 指针域(pointer field):每个结点中存储下一个结点的地址。

2. 链表和数组的区别

数组的特点:

  • 数组中的每一个元素都属于同一数据类型的;
  • 数组是一组有序数据的集合;
  • 数组是在内存中开辟一段连续的地址空间用来存放一组数据,可以用数组名加下标来访问数组中的元素; 

链表的特点:               

  • 动态地进行存储分配的一种结构;
  • 链表中的各节点在内存中的地址都是不连续的;
  • 链表是由一个个节点组成,像一条链子一样;
  • 链表中的节点一般包括两个部分:(1)用户要用的数据(2)下一个节点的地址;          

二者对比:

一个数组只能存放同一种类型的数据,而链表中就可以存放不同的数据类型;
数组中的元素地址是连续的,想删除或添加一个新的元素,十分的麻烦不灵活,而且用数组存放数据是都要先定义好数组的大小(即元素的个数),如果在定义数组时,定义小了,内存不够用,定义大了,显然会浪费内存;

链表就可以很好的解决这些问题,链表中每一项都是一个结构体,链表中各节点在内存中的地址可以是不连续的,所以你想删除或添加一个新的节点很简单和方便,直接把节点中存放的的地址拿去修改就ok了(具体怎么添加或删除放在后用代码详细讲)。因为链表是一种动态结构,所以链表在建立的时候并不用像数组一样需要提前定义大小和位置(具体怎么创建也放在后面用代码详细讲)。

二、链表静态添加和遍历

思路:

静态创建的链表节点,都是不同内存地址,是不连续的。

所以我们要在每个节点的指针域中,存储下一个节点的地址,如上图:

  • 节点 1 的next(指针域),存储的是节点 2 的地址
  • 节点 2 的next(指针域),存储的是节点 3 的地址
  • 节点 3 的next(指针域),存储的是节点 4 的地址
  • 节点 4 的next(指针域),存储的是节点 5 的地址

通过这样的操作,就可以把这 5 个节点连接在一起。

#include <stdio.h>

struct Test
{
    int data;
    struct Test *next;
};

// 打印链表(遍历链表)
void printfLink(struct Test *p) // 当前 p 存储的是 t1 的地址,也就是链表头
{
    while ( p != NULL ) // p 现是链表头节点,通过循环移动到下一个节点,直到 NULL 
    {
        printf("%d ",p->data); // 输出当前节点的 data 值
        p = p->next; // 使 p 移动至下一个节点
    }
    putchar('\n');
}

int main()
{
    // 创建节点
    struct Test t1 = {1, NULL}; // t1.data赋值为1,t1.next赋值为NULL
    struct Test t2 = {2, NULL};
    struct Test t3 = {3, NULL};
    struct Test t4 = {4, NULL};
    struct Test t5 = {5, NULL};

    // 链接节点
    t1.next = &t2; // t1.next存储t2的地址,使t1.next指向t2这个结构体变量
    t2.next = &t3;
    t3.next = &t4;
    t4.next = &t5;

    // 打印链表
    printfLink(&t1); // 将 t1(链表头)的地址传递给printfLink函数的结构体指针变量 p

    return 0;
}

三、统计链表节点个数、链表查询及修改节点

#include <stdio.h>

struct Test
{
    int data;
    struct Test *next;
};

// 打印链表
void printfLink(struct Test *p) // 当前 p 存储的是 t1 的地址,也就是链表头
{
    while ( p != NULL ) // p 现是链表头节点,通过循环移动到下一个节点,直到 NULL 
    {
        printf("%d ",p->data); // 输出当前节点的 data 值
        p = p->next; // 使 p 移动至下一个节点
    }
    putchar('\n');
}

// 统计链表个数
int statisticsNode(struct Test *head) // 当前 head 存储的是 t1 的地址,也就是链表头
{
    int cnt = 0; // 计数器,统计节点个数

    // 遍历链表,直到 head == NULL
    while ( head != NULL )
    {
        cnt++; // 记录每一个节点
        head = head->next; // 使 head 移动至下一个节点
    }

    return cnt; // 返回节点个数
}

// 查询链表
int seekNode(struct Test *head, int data) // 当前 p 存储的是 t1 的地址,也就是链表头。data:我们需要查询的节点
{
    struct Test *p = head; // 备份头节点地址

    // 遍历链表,直到 p == NULL
    while ( p != NULL )
    {
        // 判断每个节点的数据域(p->data) 是否等于 我们需要查询的节点(data)
        if( p->data == data )
        {
            return 1; // 查询到,返回 1
        }
        p = p->next; // 使 p 移动至下一个节点
    }

    return -1;// 查不到,返回 -1
}

// 修改指定节点
int modifyNode(struct Test *head, int data) // 当前 p 存储的是 t1 的地址,也就是链表头。data:我们需要修改的节点
{
    struct Test *p = head; // 备份链表头

    // 遍历链表
    while ( p != NULL )
    {
        // 判断每个节点的数据域(p->data) 是否等于 我们需要修改的节点(data)
        if( p->data == data )
        {
            // 找了,将这个节点的原数据域的数据,修改为100
            p->data = 100;
            return 1; // 返回 1,表示修改成功
        }
        p = p->next; // 使 p 移动至下一个节点
    }
    return -1; // 返回 -1,找不到这个节点
}

int main()
{
    // 创建节点
    struct Test t1 = {1, NULL}; // t1.data赋值为1,t1.next赋值为NULL
    struct Test t2 = {2, NULL};
    struct Test t3 = {3, NULL};
    struct Test t4 = {4, NULL};
    struct Test t5 = {5, NULL};

    // 链接节点
    t1.next = &t2; // t1.next存储t2的地址,使t1.next指向t2这个结构体变量
    t2.next = &t3;
    t3.next = &t4;
    t4.next = &t5;

    // 打印链表
    printfLink(&t1);

    // 统计链表个数
    int ret = statisticsNode(&t1);
    printf("链表个数:%d\n", ret);

    // 查询链表
    int seekNodeData = 3; // 需要查询的节点
    ret = seekNode(&t1, seekNodeData); // 将 t1 的地址和需要查询的节点,传递至 seekNode 函数中
    if( ret == 1 ) // 判断返回值是否为1,如 1 表示找到了,非 1 表示找不到
    {
        printf("需查询的值:%d,查询结果:%d\n", seekNodeData, ret);
    }
    else
    {
        printf("需查询的值:%d,查询结果:%d\n", seekNodeData, ret);
    }

    // 修改指定节点
    int modifyNodeData = 5; // 需要修改的节点
    printf("修改之前的链表:");
    printfLink(&t1);
    ret = modifyNode(&t1, modifyNodeData); // 将 t1 的地址和需要修改的节点,传递至 modifyNode 函数中
    printf("修改之后的链表:");
    printfLink(&t1);

    return 0;
}

四、在指定节点插入新的节点

插入一个新节点有两种方法:        

  1.  在指定节点后插入新的节点
  2.  在指定节点前插入新的节点

1.在指定节点后插入新的节点

如上图,在节点 2 的后方插入新的节点:

  1.  通过循环,遍历到指定的节点
  2. 让新节点的下一个节点,连接到节点 3
    new->next = p->next
  3. 使指定节点的下一个节点,连接到新节点
    p->next = new;
#include <stdio.h>

struct Test
{
    int data;
    struct Test *next;
};

// 打印链表
void printfLink(struct Test *p) // 当前 p 存储的是 t1 的地址,也就是链表头
{
    while ( p != NULL ) // p 现是链表头节点,通过循环移动到下一个节点,直到 NULL 
    {
        printf("%d ",p->data); // 输出当前节点的 data 值
        p = p->next; // 使 p 移动至下一个节点
    }
    putchar('\n');
}

// 在指定节点后方插入新节点
void afterInsertionNode(struct Test **head, int appointNode, struct Test *new)
{
    // 备份链表头地址
    struct Test *p = *head;

    // 遍历链表
    while ( p != NULL )
    {
        // 判断当前节点是否等于目标节点
        if( p->data == appointNode )
        {
            new->next = p->next; // 让新节点的下一个节点存储,原节点的下一个节点的地址
            p->next = new; // 让当前节点指向新节点
            return; // 找到之后直接返回
        }
        p = p->next; // 让当前节点移动到下一个节点
    }
    printf("没有找到目标节点,插入失败!\n");
}

int main()
{
    // 创建节点
    struct Test t1 = {1, NULL}; // t1.data赋值为1,t1.next赋值为NULL
    struct Test t2 = {2, NULL};
    struct Test t3 = {3, NULL};
    struct Test t4 = {4, NULL};
    struct Test t5 = {5, NULL};
    
    // 创建链表头
    struct Test *head = NULL;
    // 定义新节点并赋初值
    struct Test new = {100,NULL};

    // 链接节点
    head = &t1; // 头节点head,存储结构体变量 t1 的地址
    t1.next = &t2; // t1.next存储t2的地址,使t1.next指向t2这个结构体变量
    t2.next = &t3;
    t3.next = &t4;
    t4.next = &t5;

    // 打印链表
    printf("输出插入之前的链表:\n");
    printfLink(head);
    // 在指定节点后方插入新节点
    afterInsertionNode(&head, 2,&new);
    printf("输出插入之后的链表:\n");
    printfLink(head);

    return 0;
}

2.在指定节点的前方插入新节点

有两种情况:

  • 1.第一个节点之前插入新的节点;
  • 2.在中间的节点插入新的节点;

1.第一个节点之前插入新的节点;

 

如上图,在指定节点的节点 1,之前插入的新节点:

  1. 遍历,判断节点是否为指定节点
  2. 新节点的下一个,指向节点1的地址
    new->next = p;
  3. 因为此时新节点变成了头节点,所以此时将new的地址赋值给head
    head = new;
void forwardInsertionNode(struct Test **head, int appointNode, struct Test *new)
{
    struct Test *p = *head; // 备份链表头的地址

    // 判断第一个节点的data,是否等于目标节点
    if( p->data == appointNode )
    {
        // 将新节点的下一个节点指向,p的地址,此时new节点变成了链表头
        new->next = p;
        // 更新链表头的指向,使*head指向new的地址,让*head重新变成链表头
        *head = new;
        return;
    }
}

2.在中间的节点插入新的节点;

    如上图,如果指定节点是5,之前插入新的节点:

    思路:

    按照之前的后面插入新节点的方法,当我们遍历到指定节点 5 的时候,如果将new的下一个节点,指向目标节点,是可以连接上的,但是new的节点如果访问到指定节点的上一个节点呢?这个时候很难找到目标节点的上一个节点的地址。
    可以这么做,我们要在目标节点 5 之前插入一个新节点,比如说:现在 p 指向的是节点 4 ,节点 4 的下一个节点是目标节点 5 。那节点 4 ->next,不就是目标节点 5 吗?,节点 4 ->next->data,不就是节点 5 的data?然后将new->next指向目标节点 5 的地址,节点 4->next 指向new的地址,不就连上了。

        // 判断当前节点的下一个节点,是否为NULL
        while ( p->next != NULL )
        {
            // 判断当前节点的下一个节点的data,是否等于目标节点
            if( p->next->data == appointNode )
            {
                // 将new的下一个节点,指向原当前节点的下一个节点
                new->next = p->next;
                // 将当前节点的下一个节点指向new
                p->next = new;
                return;
            }
            p = p->next; // 偏移到下一个节点
        }

    完整代码:

    #include <stdio.h>
    
    struct Test
    {
        int data;
        struct Test *next;
    };
    
    // 打印链表
    void printfLink(struct Test *p) // 当前 p 存储的是 t1 的地址,也就是链表头
    {
        while ( p != NULL ) // p 现是链表头节点,通过循环移动到下一个节点,直到 NULL 
        {
            printf("%d ",p->data); // 输出当前节点的 data 值
            p = p->next; // 使 p 移动至下一个节点
        }
        putchar('\n');
    }
    
    // 在指定节点前方插入新节点
    void forwardInsertionNode(struct Test **head, int appointNode, struct Test *new)
    {
        struct Test *p = *head; // 备份链表的地址,
                                // *head是一个二级指针,保存的是main函数t1的地址,是链表的头地址
                                // 除非链表头发生改变,否则不要更改链表头的地址
    
        // 判断目标节点是否为链表的第一个节点
        if( p->data == appointNode )
        {
            new->next = p; // 将新节点的下一个节点指向,p的地址,此时new节点变成了链表头
            *head = new; // 更新链表头的指向,使*head指向new的地址,让*head重新变成链表头
            return; 
        }
    
        // 判断当前节点的下一个节点,是否为NULL
        while ( p->next != NULL )
        {
            // 判断当前节点的下一个节点的data,是否等于目标节点
            if( p->next->data == appointNode )
            {
                // 将new的下一个节点,指向原当前节点的下一个节点
                new->next = p->next;
                // 将当前节点的下一个节点指向new
                p->next = new;
                return;
            }
            p = p->next; // 偏移到下一个节点
        }
    }
    
    int main()
    {
        // 创建节点
        struct Test t1 = {1, NULL}; // t1.data赋值为1,t1.next赋值为NULL
        struct Test t2 = {2, NULL};
        struct Test t3 = {3, NULL};
        struct Test t4 = {4, NULL};
        struct Test t5 = {5, NULL};
        
        // 创建链表头
        struct Test *head = NULL;
        // 定义新节点并赋初值
        struct Test new = {100,NULL};
    
        // 链接节点
        head = &t1; // 头节点head,存储结构体变量 t1 的地址
        t1.next = &t2; // t1.next存储t2的地址,使t1.next指向t2这个结构体变量
        t2.next = &t3;
        t3.next = &t4;
        t4.next = &t5;
    
        // 打印链表
        printf("输出插入之前的链表:\n");
        printfLink(head);
        forwardInsertionNode(&head, 5,&new);
        printf("输出插入之后的链表:\n");
        printfLink(head);
    
        return 0;
    }

    五、删除指定节点

    有两种情况:

    1. 删除第一个节点
    2. 删除中间的节点

    1.删除第一个节点

    思路:

    head指向的是第一个节点,如果我需要删除第一个节点,需要free()释放内存,此时应当将head指向第二个节点。

        struct Test *p = *head; // 备份链表头的地址
    
        // 判断链表第一个节点的data,是否与目标节点相等
        if( p->data == appointNode )
        {
            // 将链表头指向第二个节点的地址
            *head = p->next;
            return;
        }

    2.删除中间的节点

    思路:

    如果我们删除的是节点 3,那么节点 2 应该绕过节点 3,使节点 2 连接节点 4

        // 判断当前节点的下一个节点是否为NULL
        while ( p->next != NULL )
        {
            // 判断当前节点的下一个节点的data,是否等于目标节点
            if( p->next->data == appointNode )
            {
                // 当前节点的下一个,指向当前节点的下一个节点的下一个节点
                p->next = p->next->next;
                return;
            }
            p = p->next; // 将当前节点,移动到下一个节点
        }

    完整代码:

    #include <stdio.h>
    
    struct Test
    {
        int data;
        struct Test *next;
    };
    
    // 打印链表
    void printfLink(struct Test *p) // 当前 p 存储的是 t1 的地址,也就是链表头
    {
        while ( p != NULL ) // p 现是链表头节点,通过循环移动到下一个节点,直到 NULL 
        {
            printf("%d ",p->data); // 输出当前节点的 data 值
            p = p->next; // 使 p 移动至下一个节点
        }
        putchar('\n');
    }
    
    // 删除节点
    void delectNode(struct Test **head, int appointNode)
    {
        struct Test *p = *head; // 备份链表头的地址
    
        // 判断链表第一个节点的data,是否与目标节点相等
        if( p->data == appointNode )
        {
            // 将链表头指向第二个节点的地址
            *head = p->next;
            return;
        }
    
        // 判断当前节点的下一个节点是否为NULL
        while ( p->next != NULL )
        {
            // 判断当前节点的下一个节点的data,是否等于目标节点
            if( p->next->data == appointNode )
            {
                // 当前节点的下一个,指向当前节点的下一个节点的下一个节点
                p->next = p->next->next;
                return;
            }
            p = p->next; // 将当前节点,移动到下一个节点
        }
    }
    
    int main()
    {
        // 创建节点
        struct Test t1 = {1, NULL}; // t1.data赋值为1,t1.next赋值为NULL
        struct Test t2 = {2, NULL};
        struct Test t3 = {3, NULL};
        struct Test t4 = {4, NULL};
        struct Test t5 = {5, NULL};
        
        // 创建链表头
        struct Test *head = NULL;
    
        // 链接节点
        head = &t1; // 头节点head,存储结构体变量 t1 的地址
        t1.next = &t2; // t1.next存储t2的地址,使t1.next指向t2这个结构体变量
        t2.next = &t3;
        t3.next = &t4;
        t4.next = &t5;
    
        // 打印链表
        printf("输出删除之前的链表:\n");
        printfLink(head);
        delectNode(&head, 4);
        printf("输出删除之后的链表:\n");
        printfLink(head);
    
        return 0;
    }

    六、动态创建节点 

    头插法

    如果链条为空,创建的第一个节点为链表头,然后每一次创建的新节点插在之前的链表头之前,再让新节点做为新的链表头;

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Test 
    {
    	int data;
    	struct Test *next;
    };
    
    // 头插法
    struct Test* insertionHead(struct Test *head, struct Test *new)
    {
    	// 如果head(头节点)是NULL
    	if( head == NULL )
    	{
    		// 让head指向new
    		head = new;
    	}
    	else
    	{
            // 如果head(头节点)不是NULL,那么新节点指向head,此时new为新的链表头
    		new->next = head;
            // 让head指向new,让head重新成为链表头
    		head = new;
    	}
    
    	return head; // 返回链表头的地址
    }
    
    // 动态创建链表节点
    void createNode(struct Test **head)
    {
    	struct Test *new = NULL;
    
    	while(1)
    	{
    		// 开辟内存空间
    		new = (struct Test*)malloc( sizeof(struct Test) );
    		// 判断是否开辟成功
    		if( new == NULL )
    		{
    			printf("malloc error\n");
    			exit(-1);
    		}
    		// 将new的下一个节点指向NULL
    		new->next = NULL;
    
    		printf("为新节点的数据域赋值,如果输入0,表示退出\n");
    		scanf("%d", &(new->data));
    		// 判断输入的是否为 0
    		if( new->data == 0 )
    		{
    			printf("输入0,quit\n");
    			free(new); // 释放指针
                new = NULL; // 避免悬空指针
    			return; 
    		}
    
            // 重新获取链表头的地址
    		*head = insertionHead(*head,new);
    	}
    }
    
    // 打印链表
    void printfLink(struct Test *head)
    {
    	struct Test *p = head;
    
    	while( p != NULL )
    	{
    		printf("%d ", p->data);
    		p = p->next;
    	}
    	putchar('\n');
    }
    
    int main()
    {
    	struct Test *head = NULL;
    	
    	createNode(&head);
    	printfLink(head);
    
    	return 0;
    }

    尾插法

    如果链表为空,创建的第一个节点做为链表头,然后每一次创建的新节点插在链表最后一个节点的指针域(next)中;

    #include <stdio.h>
    #include <stdlib.h>
    
    // 定义链表节点结构体
    struct Test
    {
        int data;           // 数据域
        struct Test *next;  // 指针域,指向下一个节点
    };
    
    // 在链表尾部插入新节点
    struct Test* insertTail(struct Test *head, struct Test *new)
    {
        struct Test *p = head;
    
        if (head == NULL)  // 如果链表为空,新节点即为头节点
        {
            head = new;
        }
        else
        {
            // 遍历链表,找到最后一个节点
            while (p->next != NULL)
            {
                p = p->next;
            }
            // 将新节点插入到链表尾部
            p->next = new;
        }
    
        return head;  // 返回链表头节点
    }
    
    // 创建链表节点
    void createNode(struct Test **head)
    {
        struct Test *new = NULL;
    
        while (1)
        {
            // 开辟内存空间,创建一个新节点
            new = (struct Test*)malloc(sizeof(struct Test));
            if (new == NULL)  // 检查内存分配是否成功
            {
                printf("malloc error\n");
                exit(-1);  // 内存分配失败,退出程序
            }
    
            new->next = NULL;  // 初始化新节点的指针域为NULL
    
            // 为新节点的数据域赋值
            printf("为新节点的数据域赋值,输入0,退出\n");
            scanf("%d", &(new->data));
            if (new->data == 0)  // 如果输入0,则退出循环
            {
                free(new);  // 释放内存
                new = NULL;  // 避免指针悬空
                return;
            }
    
            // 将新节点插入链表尾部
            *head = insertTail(*head, new);
        }
    }
    
    // 打印链表
    void printfLink(struct Test *head)
    {
        while (head != NULL)
        {
            printf("%d ", head->data);  // 打印当前节点的数据
            head = head->next;  // 移动到下一个节点
        }
        putchar('\n');  // 打印换行符
    }
    
    int main()
    {
        struct Test *head = NULL;  // 初始化链表头节点为NULL
    
        createNode(&head);  // 创建链表
        printfLink(head);   // 打印链表
    
        return 0;
    }

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

    如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

    相关文章

    国产化板卡设计原理图:2330-基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡

    基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡 一、板卡概述 本板卡基于 FPGAJFM7K325T 芯片&#xff0c;pin_to_pin兼容FPGAXC7K410T-2FFG900 &#xff0c;支持PCIeX8、64bit DDR3容量2GByte&#xff0c;HPC的FMC连接器&#xff0c;板卡支持PXIE标准协议&#xff0c;其中XJ3…

    【网络】HTTP协议、HTTPS协议

    HTTP与HTTPS HTTP协议概述 HTTP(超文本传输协议):工作在OSI顶层应用层,用于客户端(浏览器)与服务器之间的通信,B/S模式 无状态:每次请求独立,服务器不保存客户端状态(通过Cookie/Session扩展状态管理)。基于TCP:默认端口80(HTTP)、443(HTTPS),保证可靠传输。请…

    设计AI芯片架构的入门 研究生入行数字芯片设计、验证的项目 opentitan

    前言 这几年芯片设计行业在国内像坐过山车。时而高亢&#xff0c;时而低潮。最近又因为AI的热潮开始high起来。到底芯片行业的规律是如何&#xff1f; 我谈谈自己观点&#xff1a;芯片设计是“劳动密集型”行业。 “EDA和工具高度标准化和代工厂的工艺标准化之后&#xff0c;芯…

    K8S学习之基础十七:k8s的蓝绿部署

    蓝绿部署概述 ​ 蓝绿部署中&#xff0c;一共有两套系统&#xff0c;一套是正在提供服务的系统&#xff0c;一套是准备发布的系统。两套系统都是功能完善、正在运行的系统&#xff0c;只是版本和对外服务情况不同。 ​ 开发新版本&#xff0c;要用新版本替换线上的旧版本&…

    STM32之I2C硬件外设

    注意&#xff1a;硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器&#xff0c;此时会置状态寄存器的TXE为1&#xff0c;表示发送寄存器为空&#xff0c;然后往数据控制寄存器中一位一位的移送数…

    Linux基础--用户管理

    目录 查看用户 使用命令: id 创建用户 使用命令: useradd ​编辑 为用户设置密码 使用命令: passwd ​编辑 删除用户 使用命令: userdel 创建用户组 使用命令: groupadd 删除用户组 使用命令: groupdel 用户设置 使用命令: usermod 将用户从组中去除 使用…

    VSTO(C#)Excel开发3:Range对象 处理列宽和行高

    初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

    本地YARN集群部署

    请先完成HDFS的前置部署&#xff0c;部署方式可查看:本地部署HDFS集群https://blog.csdn.net/m0_73641796/article/details/145998092?spm1001.2014.3001.5502 部署说明 组件配置文件启动进程备注Hadoop HDFS需修改 需启动: NameNode作为主节点 DataNode作为从节点 Secondary…

    每日一练之移除链表元素

    题目&#xff1a; 画图解析&#xff1a; 方法&#xff1a;双指针 解答代码&#xff08;注&#xff1a;解答代码带解析&#xff09;&#xff1a; //题目给的结构体 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* }…

    黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!

    调色教程 针对人像、静物以及户外旅拍照片&#xff0c;运用 Lightroom 软件进行风格化调色工作。旨在通过软件中的多种工具&#xff0c;如基本参数调整、HSL&#xff08;色相、饱和度、明亮度&#xff09;调整、曲线工具等改变照片原本的色彩、明度、对比度等属性&#xff0c;将…

    【GPT入门】第8课 大语言模型的自洽性

    【GPT入门】第8课 大语言模型的自洽性 1.自洽性概念2.代码&#xff08;观察执行结果&#xff09;3.自洽性核心思想 1.自洽性概念 大模型的自洽性&#xff08;self - consistency&#xff09;是指在推理阶段&#xff0c;大模型通过生成多个答案并选择出现频率最高的那个&#x…

    深度学习(斋藤康毅)学习笔记(六)反向传播3

    上一篇文章介绍了反向传播的自动化&#xff0c;但也存在一些问题&#xff0c;本章用于说明这些问题&#xff0c;并修改原有框架&#xff0c;使其支持复杂计算图的运行&#xff1a; 问题一&#xff1a;重复使用一个变量&#xff0c;梯度不会累计 也就是说&#xff0c;反向传播时…

    3.6c语言

    #define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完数\n", j);}}return 0; }#de…

    element-plus中table组件的使用

    1、table组件的基本使用 注意&#xff1a; ①对象集合&#xff0c;要从后端查询。 ②prop是集合中的对象的属性名&#xff1b;label是表格表头的名称。 2、将性别一列的71转为男&#xff0c;72转为女 问题描述&#xff1a; 解决步骤&#xff1a; ①将el-table-column变成双标签…

    .NET CAD 二次开发中的 Transform 与数学矩阵详解

    .NET CAD 二次开发中的 Transform 与数学矩阵详解 一、Transform 的定义与作用 在 .NET CAD 二次开发中,Transform 是通过数学矩阵对图形实体进行几何变换的核心机制,包括平移、旋转、缩放、镜像和切变等操作。这些操作通过矩阵乘法实现,能够高效地修改图形的位置、方向和…

    【js逆向】iwencai国内某金融网站实战

    地址&#xff1a;aHR0cHM6Ly93d3cuaXdlbmNhaS5jb20vdW5pZmllZHdhcC9ob21lL2luZGV4 在搜索框中随便输入关键词 查看请求标头&#xff0c;请求头中有一个特殊的 Hexin-V,它是加密过的&#xff1b;响应数据包中全是明文。搞清楚Hexin-V的值是怎么生成的&#xff0c;这个值和cooki…

    STM32之ADC

    逐次逼近式ADC&#xff1a; 左边是8路输入通道&#xff0c;左下是地址锁存和译码&#xff0c;可将通道的地址锁存进ADDA&#xff0c;ADDB&#xff0c;ADDC类似38译码器的结构&#xff0c;ALE为锁存控制键&#xff0c;通道选择开关可控制选择单路或者多路通道&#xff0c;DAC为…

    【Linux内核系列】:深入解析输出以及输入重定向

    &#x1f525; 本文专栏&#xff1a;Linux &#x1f338;作者主页&#xff1a;努力努力再努力wz ★★★ 本文前置知识&#xff1a; 文件系统以及文件系统调用接口 用c语言简单实现一个shell外壳程序 内容回顾 那么在此前的学习中&#xff0c;我们对于Linux的文件系统已经有了…

    基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

    《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

    无人机扩频技术对比!

    一、技术原理与核心差异 FHSS&#xff08;跳频扩频&#xff09; 核心原理&#xff1a;通过伪随机序列控制载波频率在多个频点上快速跳变&#xff0c;收发双方需同步跳频序列。信号在某一时刻仅占用窄带频谱&#xff0c;但整体覆盖宽频带。 技术特点&#xff1a; 抗干扰…