数据结构(C语言版)线性表-链表

链表

​ 线性表链式存储结构的特点是:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。 ​ 为了表示每个数据元素 a i 与其直接后继数据元素 ai+1 之间的逻辑关系,对数据元素 ai 来说,除了其本身的信息之外,还需要存储一个指示其直接后继的信息(直接后继的存储位置)。这两部分信息组成数据元素 a 的存储映像,称为节点 ( node )。 ​ 结点包括两个域:其中存储数据元素信息的称为数据域 ;存储直接后继存储位置有域称为指针域。指针域中存储的信息称作指针或链。 ​ n个结点[ a (1< =i <= n )的存储映像]链接成一个链表,即为线性表( ai ,a2,..,an )。

存储结构

  • 头节点:可选,在表头前额外添加的空节点(简化边界操作,如删除第一个节点);
  • 头指针:指向链表第一个节点(含头节点则指向头节点);
  • 尾节点:最后一个节点,指针域为NULL(循环链表指向头节点);
  • 空链表:头指针为NULL(或头节点指针域为NULL)。
c 复制代码
typedef int ElemType;

// 单链表节点结构体
typedef struct node {
	ElemType data;// 数据域:存储元素值
	struct node* next;// 指针域:指向下一个节点
}Node;

单链表

初始化

c 复制代码
Node* initList()
{
	Node* head =(Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}

遍历

c 复制代码
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

插入数据

头插法

从表头插入节点

c 复制代码
int insertHead(Node* L, ElemType e)
{
	//创建新节点并分配内存
	Node* p = (Node*)malloc(sizeof(Node));
	//赋值数据域
	p->data = e;

	p->next = L->next;// 新节点指向原表头有效节点
	L->next = p;// 头节点指向新节点,完成插入
	return 1;
}

头插法遍历

完整代码:

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}

//头插法
int insertHead(Node* L, ElemType e)
{
	//创建新节点并分配内存
	Node* p = (Node*)malloc(sizeof(Node));
	//赋值数据域
	p->data = e;

	p->next = L->next;
	L->next = p;
	return 1;
}

void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	Node* list = initList();
	insertHead(list, 10);
	insertHead(list, 20);
	insertHead(list, 30);
	PrintNode(list);
	return 0;
}

运行结果:

30 20 10

尾插法
c 复制代码
//找到尾节点
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}
c 复制代码
//插入
//(1)返回尾节点---完整代码1
Node* insertTail(Node* tail, ElemType e)
{
	Node* p = (Node*)malloc(sizeof(Node));
    //赋值并连接节点
	p->data = e;
	tail->next = p;//尾节点的next指向新创建的节点p
	p->next = NULL;//节点p变成尾节点
	return p;
}

//(2)插入函数中调用get_tail---完整代码2
int insertTail(Node* L, ElemType e) 
{
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}

完整代码1---插入函数返回尾节点

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}

//尾插法--找到尾节点
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

Node* insertTail(Node* tail, ElemType e)
{
	Node* p = (Node*)malloc(sizeof(Node));
	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	return p;//返回尾节点
}


//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}


int main()
{
	Node* list = initList();
	Node* tail=get_tail(list);
	tail=insertTail(tail, 10);
	tail=insertTail(tail, 20);
	tail=insertTail(tail, 30);
	PrintNode(list);
	return 0;
}

运行结果:

10 20 30

完整代码2---inertTail中调用get_tail

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}

//尾插法--找到尾节点
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

int insertTail(Node* L, ElemType e) {
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}

//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}


int main()
{
	Node* list = initList();

	insertTail(list, 10);
	insertTail(list, 20);
	insertTail(list, 30);
	PrintNode(list);
	return 0;
}

运行结果:

10 20 30

在指定位置插入数据
c 复制代码
int insertNode(Node* L, int pos, ElemType e)
{
	Node* p = L;//用来保存插入位置的前驱节点

	//遍历找到插入位置的前驱节点
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;// 先移动节点
		if (p == NULL)// 移动后检查是否越界
		{
			return 0;// pos 超出链表长度,返回失败
		}
	}

	Node* q = (Node*)malloc(sizeof(Node));//创建一个要插入的新节点
	q->data = e;//赋值
	q->next = p->next;//1 新节点指向下一节点
	p->next = q;//2 前驱节点指向新节点
	return 1;
}

完整代码

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}
 
 
// 尾插法
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

int insertTail(Node* L, ElemType e) {
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}
 
 

//在指定位置插入数据
int insertNode(Node* L, int pos, ElemType e)
{
	Node* p = L;//用来保存插入位置的前驱节点

	//遍历找到插入位置的前驱节点
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;// 先移动节点
		if (p == NULL)// 移动后检查是否越界
		{
			return 0;// pos 超出链表长度,返回失败
		}
	}

	Node* q = (Node*)malloc(sizeof(Node));//创建一个要插入的新节点
	q->data = e;//赋值
	q->next = p->next;//1
	p->next = q;//2
	return 1;
}



//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	Node* list = initList();
	insertTail(list, 10);
	insertTail(list, 20);
	insertTail(list, 30);
	PrintNode(list);
	insertNode(list, 2, 15);
	PrintNode(list);
	return 0;
}

运行结果:

10 20 30 10 15 20 30

删除节点

c 复制代码
//删除节点
int delectNode(Node* L, int pos) {

	//要删除节点的前驱
	Node* p = L;
	//遍历找到要删除节点的前驱
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;
		if (p == NULL)
		{
			return 0;
		}
	}

	if (p->next == NULL)
	{
		printf("要删除的位置错误\n");
			return 0;
	}

	Node* q = p->next; //记录被删除的节点q

	p->next = q->next; //(将被删除的节点的前驱)p指向被删除结点的后继
	free(q);//释放被删除节点的内存空间
	return 1;
}

完整代码:

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}
 
 
// 尾插法
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

int insertTail(Node* L, ElemType e) {
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}
 
 

//在指定位置插入数据
int insertNode(Node* L, int pos, ElemType e)
{
	Node* p = L;//用来保存插入位置的前驱节点

	//遍历找到插入位置的前驱节点
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;// 先移动节点
		if (p == NULL)// 移动后检查是否越界
		{
			return 0;// pos 超出链表长度,返回失败
		}
	}

	Node* q = (Node*)malloc(sizeof(Node));//创建一个要插入的新节点
	q->data = e;//赋值
	q->next = p->next;//1
	p->next = q;//2
	return 1;
}

//删除节点
int delectNode(Node* L, int pos) {

	//要删除节点的前驱
	Node* p = L;
	//遍历找到要删除节点的前驱
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;
		if (p == NULL)
		{
			return 0;
		}
	}

	if (p->next == NULL)
	{
		printf("要删除的位置错误\n");
		return 0;
	}

	Node* q = p->next; //记录被删除的节点q

	p->next = q->next; //(将被删除的节点的前驱)p指向被删除结点的后继
	free(q);//释放被删除节点的内存空间
	return 1;
}

//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	Node* list = initList();
	insertTail(list, 10);
	insertTail(list, 20);
	insertTail(list, 30);
	printf("原链表:");
	PrintNode(list);
    
	insertNode(list, 2, 15);
	printf("插入后");
	PrintNode(list);
    
	delectNode(list, 2);
	printf("删除后:");
	PrintNode(list);
	return 0;
}

运行结果:

原链表:10 20 30 插入后10 15 20 30 删除后:10 20 30

按值查找

c 复制代码
Node* findByValue(Node* L, ElemType e)
{
	if (L == NULL)
	{
		return NULL;
	}
	Node* p = L;
	while (p != NULL) {
		p = p->next;
		if (p->data == e)
		{
			return p;
		}
	}
	printf("查找失败:未找到元素%d\n", e);
	return NULL;
}

完整代码:

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}
 
 
// 尾插法
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

int insertTail(Node* L, ElemType e) {
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}
 
 

//在指定位置插入数据
int insertNode(Node* L, int pos, ElemType e)
{
	Node* p = L;//用来保存插入位置的前驱节点

	//遍历找到插入位置的前驱节点
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;// 先移动节点
		if (p == NULL)// 移动后检查是否越界
		{
			return 0;// pos 超出链表长度,返回失败
		}
	}

	Node* q = (Node*)malloc(sizeof(Node));//创建一个要插入的新节点
	q->data = e;//赋值
	q->next = p->next;//1
	p->next = q;//2
	return 1;
}

//删除节点
int delectNode(Node* L, int pos) {

	//要删除节点的前驱
	Node* p = L;
	//遍历找到要删除节点的前驱
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;
		if (p == NULL)
		{
			return 0;
		}
	}

	if (p->next == NULL)
	{
		printf("要删除的位置错误\n");
		return 0;
	}

	Node* q = p->next; //记录被删除的节点q

	p->next = q->next; //(将被删除的节点的前驱)p指向被删除结点的后继
	free(q);//释放被删除节点的内存空间
	return 1;
}

//按值查找
Node* findByValue(Node* L, ElemType e)
{
	if (L == NULL)
	{
		return NULL;
	}
	Node* p = L;
	while (p != NULL) {
		p = p->next;
		if (p->data == e)
		{
			return p;
		}
	}
	printf("查找失败:未找到元素%d\n", e);
	return NULL;
}

//获取节点长度
int NodeLength(Node*L) 
{
	Node* p = L;
	int len = 0;
	while (p != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}


//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}


//释放链表
void freeList(Node* L) {
	Node* p = L->next;
	Node* q;

	while (p != NULL) {
		q = p->next;
		free(p);
		p = q;
	}
	L->next = NULL;
}



int main()
{
	Node* list = initList();
	insertTail(list, 10);
	insertTail(list, 20);
	insertTail(list, 30);
	printf("原链表:");
	PrintNode(list);

	insertNode(list, 2, 15);
	printf("插入后");
	PrintNode(list);

	delectNode(list, 2);
	printf("删除后:");
	PrintNode(list);

	Node*find_node=findByValue(list, 20);
	if (find_node != NULL) {
		printf("找到元素:%d\n", find_node->data);
	}
	return 0;
}

运行结果:

原链表:10 20 30 插入后10 15 20 30 删除后:10 20 30 找到元素:20

获取链表长度

c 复制代码
//获取节点长度
int LinklistLength(Node*L) 
{
	Node* p = L;//包含头节点
    
    //计算有效节点长度
    //Node* p = L->next; //跳过头节点,指向第一个有效节点
    
	int len = 0;
	while (p != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}

完整代码:

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}
 
 
// 尾插法
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

int insertTail(Node* L, ElemType e) {
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}
 
 

//在指定位置插入数据
int insertNode(Node* L, int pos, ElemType e)
{
	Node* p = L;//用来保存插入位置的前驱节点

	//遍历找到插入位置的前驱节点
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;// 先移动节点
		if (p == NULL)// 移动后检查是否越界
		{
			return 0;// pos 超出链表长度,返回失败
		}
	}

	Node* q = (Node*)malloc(sizeof(Node));//创建一个要插入的新节点
	q->data = e;//赋值
	q->next = p->next;//1
	p->next = q;//2
	return 1;
}

//删除节点
int delectNode(Node* L, int pos) {

	//要删除节点的前驱
	Node* p = L;
	//遍历找到要删除节点的前驱
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;
		if (p == NULL)
		{
			return 0;
		}
	}

	if (p->next == NULL)
	{
		printf("要删除的位置错误\n");
		return 0;
	}

	Node* q = p->next; //记录被删除的节点q

	p->next = q->next; //(将被删除的节点的前驱)p指向被删除结点的后继
	free(q);//释放被删除节点的内存空间
	return 1;
}

//按值查找
Node* findByValue(Node* L, ElemType e)
{
	if (L == NULL)
	{
		return NULL;
	}
	Node* p = L;
	while (p != NULL) {
		p = p->next;
		if (p->data == e)
		{
			return p;
		}
	}
	printf("查找失败:未找到元素%d\n", e);
	return NULL;
}

//获取节点长度
int LinklistLength(Node*L) 
{
	Node* p = L;//未跳过头节点
	int len = 0;
	while (p != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}


//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	Node* list = initList();
	insertTail(list, 10);
	insertTail(list, 20);
	insertTail(list, 30);
	printf("原链表:");
	PrintNode(list);
    
	insertNode(list, 2, 15);
	printf("插入后");
	PrintNode(list);
    
	delectNode(list, 2);
	printf("删除后:");
	PrintNode(list);
    
    Node*find_node=findByValue(list, 20);
	if (find_node != NULL) {
		printf("找到元素:%d\n", find_node->data);
	}
    
	printf("链表长度为%d\n", LinklistLength(list));
	return 0;
}

运行结果:

原链表:10 20 30 插入后10 15 20 30 删除后:10 20 30 找到元素:20 链表长度为4

释放链表

需逐个释放节点,避免内存泄漏。

c 复制代码
//释放链表--头节点保留
void freeList(Node* L) {
	Node* p = L->next;
	Node* q;

	while (p != NULL) {
		q = p->next;
		free(p);
		p = q;
	}
	L->next = NULL;
}

完整代码:

c 复制代码
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;

typedef struct node {
	ElemType data;
	struct node* next;
}Node;

//初始化
Node* initList()
{
	Node* head = (Node*)malloc(sizeof(Node));
	head->data = 0;
	head->next = NULL;
	return head;
}
 
 
// 尾插法
Node* get_tail(Node* L) {
	Node* p = L;
	while (p->next != NULL) {
		p = p->next;
	}
	return p;
}

int insertTail(Node* L, ElemType e) {
	Node* tail=get_tail(L);
	Node* p = (Node*)malloc(sizeof(Node));

	//赋值并连接节点
	p->data = e;
	tail->next = p;
	p->next = NULL;
	
	return 1;
}
 
 

//在指定位置插入数据
int insertNode(Node* L, int pos, ElemType e)
{
	Node* p = L;//用来保存插入位置的前驱节点

	//遍历找到插入位置的前驱节点
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;// 先移动节点
		if (p == NULL)// 移动后检查是否越界
		{
			return 0;// pos 超出链表长度,返回失败
		}
	}

	Node* q = (Node*)malloc(sizeof(Node));//创建一个要插入的新节点
	q->data = e;//赋值
	q->next = p->next;//1
	p->next = q;//2
	return 1;
}

//删除节点
int delectNode(Node* L, int pos) {

	//要删除节点的前驱
	Node* p = L;
	//遍历找到要删除节点的前驱
	for (int i = 0; i < pos - 1; i++)
	{
		p = p->next;
		if (p == NULL)
		{
			return 0;
		}
	}

	if (p->next == NULL)
	{
		printf("要删除的位置错误\n");
		return 0;
	}

	Node* q = p->next; //记录被删除的节点q

	p->next = q->next; //(将被删除的节点的前驱)p指向被删除结点的后继
	free(q);//释放被删除节点的内存空间
	return 1;
}

//按值查找
Node* findByValue(Node* L, ElemType e)
{
	if (L == NULL)
	{
		return NULL;
	}
	Node* p = L;
	while (p != NULL) {
		p = p->next;
		if (p->data == e)
		{
			return p;
		}
	}
	printf("查找失败:未找到元素%d\n", e);
	return NULL;
}

//获取节点长度
int LinklistLength(Node*L) 
{
	Node* p = L;
	int len = 0;
	while (p != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}


//遍历
void PrintNode(Node* L) 
{
	Node* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}


//释放链表
void freeList(Node* L) {
	Node* p = L->next;
	Node* q;

	while (p != NULL) {
		q = p->next;
		free(p);
		p = q;
	}
	L->next = NULL;
}



int main()
{
	Node* list = initList();
	insertTail(list, 10);
	insertTail(list, 20);
	insertTail(list, 30);
	printf("原链表:");
	PrintNode(list);
    
	insertNode(list, 2, 15);
	printf("插入后");
	PrintNode(list);
    
	delectNode(list, 2);
	printf("删除后:");
	PrintNode(list);
    
    Node*find_node=findByValue(list, 20);
	if (find_node != NULL) {
		printf("找到元素:%d\n", find_node->data);
	}
    
	printf("链表长度为%d\n", LinklistLength(list));
    
	freeList(list);
	printf("释放后链表长度为%d\n", NodeLength(list));
	return 0;
}

运行结果:

原链表:10 20 30 插入后10 15 20 30 删除后:10 20 30 找到元素:20 链表长度为4 释放后链表长度为1

单链表 vs 顺序表 核心对比

特性 单链表 顺序表
存储方式 非连续,节点 + 指针 连续数组
随机访问 不支持(O(n) 支持(O(1)
插入 / 删除 无需移动元素(O(1) 需移动元素(O(n)
内存利用率 按需分配(无浪费) 可能浪费(静态表)或扩容
缓存友好性 差(内存分散) 好(连续存储)
实现复杂度 较高(指针操作) 较低(数组操作)

拓展

循环单链表

  • 尾节点的next指向头节点(而非NULL);
  • 优势:遍历可从任意节点开始,无需回到头指针;
  • 判空:head->next == head(带头节点)。

2. 双向链表

  • 节点新增prev指针(指向前驱节点);

  • 优势:可双向遍历,删除节点无需找前驱(O(1));

  • 结构体定义:

    c 复制代码
    typedef struct DNode {
        ElemType data;
        struct DNode *prev; // 前驱指针
        struct DNode *next; // 后继指针
    } DNode, *DLinkList;
相关推荐
肖邦德夜曲4 小时前
1.强化学习基本概念
机器学习·强化学习
荒野火狐5 小时前
【强化学习】关于PPO收敛问题
python·深度学习·机器学习·强化学习
华师数据学院·王嘉宁1 天前
DeepSeek-Math-V2解读:稠密Reward信号回归到RLVR
大语言模型·强化学习·大模型推理
强化学习与机器人控制仿真1 天前
Holosoma 开源人形机器人强化学习训练部署框架
人工智能·stm32·神经网络·机器人·强化学习·具身智能·人形机器人
肖邦德夜曲2 天前
8.IsaacGymEnvs (NVIDIA 官方)的shadow灵巧手强化学习
强化学习·灵巧手
emacs5lisp2 天前
基于强化学习的自动驾驶控制
神经网络·自动驾驶·强化学习·carla·智能体
铮铭4 天前
扩散模型简介:The Annotated Diffusion Model
人工智能·机器人·强化学习·世界模型
七牛云行业应用4 天前
告别RLHF?DeepSeek过程奖励(PRM)架构解析与推理数据流设计
人工智能·强化学习·大模型架构·deepseek
iiiiii115 天前
【论文阅读笔记】IDAQ:离线元强化学习中的分布内在线适应
论文阅读·人工智能·笔记·学习·算法·机器学习·强化学习