C语言: 链表-1

链表的定义:

链表是一种常见的重要的数据结构;它是动态地进行存储分配的一种结构。

链表示意图:

定义一个简单链表

/*
  File Name : linknode.h
  定义链表结构体:UserInfo

*/

/*
 链表结构体:
 声明:age (年龄)
	  name	(姓名)
	  next (下一个节点地址)
*/
struct UserInfo
{
	//年龄
	int age;
	//姓名
	char *name;
	//存储下一个链表节点地址
	struct UserInfo* next;
};
//简写链表结构体声明
typedef struct UserInfo USER;

一 简单链表的静态模式和动态模式:

代码实现:

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

struct  Info
{
	int num;
	char flag;
	char* msg;
	void* pNext;
};

//静态模式
void staticModel()
{
	struct  Info info1;
	info1.num = 10;
	info1.flag = 'Y';
	info1.msg = "静态模式";
	info1.pNext = &(info1.num);
	printf("静态模式实现 num=%d, flag=%c , msg=%s , pNext=%p \n", info1.num, info1.flag, info1.msg,info1.pNext);
}

void dynamicModel()
{
	struct  Info* info1;
	info1 = (struct  Info*)malloc(sizeof(struct Info));//分配内存 malloc 返回值是 vold 空指针类型,必须进行强制转换
	(*info1).num = 20;  //等价形式 info1->num = 20; (*info1)加上 * 号就取出了结构体的内容,等价于一个结构体。
	(*info1).flag = 'N'; //等价形式 info1->flag = 'N';
	(*info1).msg = "动态模式";//等价形式 info1->msg = "动态模式";
	(*info1).pNext = &((*info1).num); //取地址 ,等价于 info1->pNext = &(info1->num);
	

	printf("静态模式实现 num=%d, flag=%c , msg=%s , pNext=%p \n", info1->num, info1->flag, info1->msg, info1->pNext);
}

void main()
{
	printf("静态模式实现:\n");
	staticModel();
	printf("动态模式实现:\n");
	dynamicModel();

	system("pause");
}

输出:

在实际运用中一般都使用动态链表来存储数据

 

二 动态简单链表的 增删改查:

链表结构和函数声明:

/*
链表结构体和函数声明头文件 : linknode.h
*/

#include<stdio.h>
#include<stdlib.h>
/*
 链表结构体:
 声明:age (年龄)
	  name	(姓名)
	  next (下一个节点地址)
*/
struct UserInfo
{
	//年龄
	int age;
	//姓名
	char *name;
	//存储下一个链表节点地址
	struct UserInfo* next;
};
//简写链表结构体声明
typedef struct UserInfo USER;

/*
显示链表所有元素
	参数:
		USER* pUser_head:头节点
	返回:
		无
*/
void showAll(USER* pUser_head);

/*
添加节点元素
	参数:
		USER** pUser_head:头节点
		int iage:年龄
		char *iname:姓名
	返回:
		无
*/
void add(USER** pUser_head, int iage, char* iname);

/*
链表逆转
	参数:
		USER* pUser_head :头节点指针
	返回:
		USER* pUser_head :头节点指针

*/
USER* reversed(USER* pUser_head);

/*
排序,根据链表数据结构 age(年龄)进行
	参数:
		USER* pUser_head :头节点指针地址
		char flag :排序标志 '>'从大到小 ;'<' 从小到达
	返回:
		无
*/
void sort(USER* pUser_head, char flag);

/*
统计链表个数
	参数:
		USER* pUser_head :头节点指针地址
	返回:
		int :元素个数
*/
int count(USER* pUser_head);

/*
根据年龄检索链表元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:检索条件,年龄
	返回:
		USER* :元素节点指针
*/
USER* searchOfAge(USER* pUser_head, int age);

/*
根据姓名检索链表元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:检索条件,姓名
	返回:
		USER* :元素节点指针
*/
USER* searchOfName(USER* pUser_head, char * name);

/*
修改节点元素姓名
	参数:
		USER* pUser_head :头节点指针地址
		char* oldname:旧名称
		char* newname:新名称
	返回(int):
		1:修改成功
		0:未找到元素
*/
int changeByName(USER* pUser_head, char* oldname, char* newname);

/*
 根据年龄定位元素并元素前面插入新节点元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:年龄(定位)
		int iage:新元素的年龄
		char* iname:新元素的姓名
	返回:
		链表头指针
*/
USER* headInsert(USER* pUser_head,int age, int iage, char* iname);

/*
 根据姓名定位元素并元素后插入新节点元素
	参数:
		USER* pUser_head :头节点指针地址
		char* name:姓名(定位)
		int iage:新元素的年龄
		char* iname:新元素的姓名
	返回:
		链表头指针
*/
USER* backInsert(USER* pUser_head, char* name, int iage, char* iname);


/*
修改节点元素年龄
	参数:
		USER* pUser_head :头节点指针地址
		int oldage:旧 年龄
		int newage:新 年龄
	返回(int):
		1:修改成功
		0:未找到元素
*/
int changeByAge(USER* pUser_head, int oldage, int newage);

/*
删除链表
	参数:
		USER* pUser_head :头节点指针地址
	返回:
		无
*/
void* freeAll(USER* pUser_head);

/*
根据年龄删除链表节点元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:年龄
	返回:
		USER* :头节点指针
*/
USER* deleteByAge(USER* pUser_head, int age);

/*
根据姓名删除链表节点元素
	参数:
		USER* pUser_head :头节点指针地址
		char * name:姓名
	返回:
		USER* :头节点指针
*/
USER* deleteByName(USER* pUser_head, char* name);

/*
    冒泡排序
	参数:
		USER* pUser_head :头节点指针地址
		
	返回:
		 无
*/
void bubbleSort(USER* pUser_head);


/*
	快速排序1(双冒泡)
	参数:
		USER* pUser_head :头节点指针地址
		USER* pUser_back :尾节点(默认 NULL)
	返回:
		 无
*/
void quickSort(USER* pUser_head, USER* pUser_back);


/*
	快速排序2(双冒泡), 递归
	参数:
		USER* pUser_head :头节点指针地址
		USER* pUser_back :尾节点(默认 NULL)
	返回:
		 无
*/
void quickSort2(USER* begin, USER* end);

链表函数实现源文件:

/*
	链表函数实现源文件:: linknode.c
*/

#include"linknode.h"

/*
显示链表所有元素
	参数:
		USER* pUser_head:头节点
	返回:
		无
*/
void showAll(USER* pUser_head)
{
	if (pUser_head == NULL)
	{
		printf("链表元素为空!\n");
		return;
	}
	else
	{
		while (pUser_head != NULL)
		{
			printf("\n 年龄= %d , 姓名= %s ", pUser_head->age, pUser_head->name);//输出当前节点
			pUser_head = pUser_head->next; //指针不断向前循环
		}
	}
	
}

/*
添加节点元素
	参数:
		USER** pUser_head:头节点
		int iage:年龄
		char *iname:姓名
	返回:
		无
*/
void add(USER** pUser_head, int iage, char *iname)
{
	if (*pUser_head == NULL)//如果头节点指针为空
	{
		USER* newNode = (USER*)malloc(sizeof(USER)); //分配空间
		newNode->age = iage;
		newNode->name = iname;
		newNode->next = NULL;
		*pUser_head = newNode;
	}
	else //如果头节点不为空,找到链表尾部插入数据
	{
		USER* p = *pUser_head;
		while (p->next!=NULL) //结束条件 p->next!=NULL 不是 p!=NULL
		{
			p = p->next; //循环指向下以个节点,直到为空,说明到最后一个节点(链表最后节点指向为空)
		}
		USER* newNode = (USER*)malloc(sizeof(USER)); //分配空间
		newNode->age = iage;
		newNode->name = iname;
		newNode->next = NULL;
		p->next = newNode;//将节点连接到末尾
	}
}

/*
链表逆转
	参数:
		USER* pUser_head :头节点指针
	返回:
		USER* pUser_head :头节点指针

*/
USER* reversed(USER* pUser_head)
{
	USER* pU1, * pU2, * pU3; //定义三个辅助指针变量
	pU1 = pU2 = pU3 = NULL;
	if (pUser_head == NULL || pUser_head->next == NULL) //如果头节点为空,或者只有一个元素
	{
		return pUser_head;
	}
	pU1 = pUser_head;
	pU2 = pUser_head->next;
	while (pU2!=NULL) //pU2!=NULL 说明没有节点
	{
		pU3 = pU2->next; 
		pU2->next = pU1;//指向前一个节点

		//指针向前移动,从第二个元素开始到最最后一个元素,全部指向它前面的节点
		pU1 = pU2;
		pU2 = pU3;
	}
	pUser_head->next = NULL; //代表链表结束,指向为空
	pUser_head = pU1; //pU1 循环后指向最后一个节点
	return pUser_head;
}

/*
排序,根据链表数据结构 age(年龄)进行
	参数:
		USER* pUser_head :头节点指针地址
		char flag :排序标志 '>'从大到小 ;'<' 从小到达
	返回:
		无
*/
void sort(USER* pUser_head, char flag)
{
	if (pUser_head == NULL || pUser_head->next == NULL)//如果链表为空,或只有一个元素
	{
		return;
	}
	if (flag == '>') //从大到小
	{
		for (USER* p1 = pUser_head; p1 != NULL; p1 = p1->next) //遍历链表所有节点
		{
			for (USER* p2 = pUser_head; p2 != NULL; p2 = p2->next)//遍历链表所有节点
			{
				if (p1->age < p2->age) //满足条件交换遍历
				{
					USER temp;
					temp.age = p1->age;
					temp.name = p1->name;

					p1->age = p2->age;
					p1->name = p2->name;

					p2->age = temp.age;
					p2->name = temp.name;
				}
			}
		}
	}
	if (flag == '<')//从小到达
	{
		for (USER* p1 = pUser_head; p1 != NULL; p1 = p1->next) //遍历链表所有节点
		{
			for (USER* p2 = pUser_head; p2 != NULL; p2 = p2->next)//遍历链表所有节点
			{
				if (p1->age > p2->age) //满足条件交换遍历
				{
					USER temp;
					temp.age = p1->age;
					temp.name = p1->name;

					p1->age = p2->age;
					p1->name = p2->name;

					p2->age = temp.age;
					p2->name = temp.name;
				}
			}
		}
	}

}

/*
统计链表个数
	参数:
		USER* pUser_head :头节点指针地址
	返回:
		int :元素个数
*/
int count(USER* pUser_head)
{
	int num = 0;
	while (pUser_head!=NULL)
	{
		num++;
		pUser_head = pUser_head->next;
	}
	return num;
}

/*
根据年龄检索链表元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:检索条件,年龄
	返回:
		USER* :元素节点指针
*/
USER* searchOfAge(USER* pUser_head, int age)
{
	USER* node = NULL;
	if (pUser_head != NULL)
	{
		while (pUser_head!=NULL)
		{
			if (age == pUser_head->age)
			{
				node = pUser_head;
				break;
			}
			pUser_head = pUser_head->next;//指针向前
		}
	}
	return node;
}

/*
根据姓名检索链表元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:检索条件,姓名
	返回:
		USER* :元素节点指针
*/
USER* searchOfName(USER* pUser_head, char* name)
{
	USER* node = NULL;
	if (pUser_head != NULL)
	{
		while (pUser_head != NULL)
		{
			if (name == pUser_head->name)
			{
				node = pUser_head;
				break;
			}
			pUser_head = pUser_head->next;//指针向前
		}
	}
	return node;
}

/*
修改节点元素姓名
	参数:
		USER* pUser_head :头节点指针地址
		char* oldname:旧名称
		char* newname:新名称
	返回(int):
		1:修改成功
		0:未找到元素
*/
int changeByName(USER* pUser_head, char* oldname, char* newname)
{
	if (pUser_head == NULL)
	{
		return 0;
	}
	USER *p= searchOfName(pUser_head, oldname);
	if (p == NULL)
	{
		return 0;
	}
	p->name = newname;
	return 1;
}

/*
修改节点元素年龄
	参数:
		USER* pUser_head :头节点指针地址
		int oldage:旧 年龄
		int newage:新 年龄
	返回(int):
		1:修改成功
		0:未找到元素
*/
int changeByAge(USER* pUser_head, int oldage, int newage)
{
	if (pUser_head == NULL)
	{
		return 0;
	}
	USER* p = searchOfAge(pUser_head, oldage);
	if (p == NULL)
	{
		return 0;
	}
	p->age = newage;
	return 1;
}


/*
 根据年龄定位元素并元素 “前” 面插入新节点元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:年龄(定位)
		int iage:新元素的年龄
		char* iname:新元素的姓名
	返回:
		链表头指针
*/
USER* headInsert(USER* pUser_head, int age, int iage, char* iname)
{
	USER* p1, * p2;
	p1 = p2 = NULL;
	p1 = pUser_head;
	while (p1 != NULL)
	{
		if (p1->age == age)//找到指定节点元素
		{
			break; //结束循环
		}
		else
		{
			p2 = p1;//记录当前节点的前一个节点
			p1 = p1->next; //当前节点指针向前移动
		}
	}
	if (p1 == pUser_head) //如果头节点前面插入节点
	{
		USER* pnode = (USER*)malloc(sizeof(USER)); //分配存储空间
		pnode->age = iage;
		pnode->name = iname;
		pnode->next = pUser_head; //新节点链接指向原来第一个节点
		pUser_head = pnode;//改变头节点指针指向新节点
		
	}
	else //其他节点满足要求
	{
		USER* pnode = (USER*)malloc(sizeof(USER)); //分配存储空间
		pnode->age = iage;
		pnode->name = iname;
		pnode->next = p1; //新节点链接 指向满足要求的节点
		p2->next = pnode; //p2 存储了当前满足要求的前一个元素节点,p1 存储了满足要求的节点, 所以,p2 的链接指向新节点
		
	}
	return pUser_head;
}

/*
 根据姓名定位元素并元素 “后” 插入新节点元素
	参数:
		USER* pUser_head :头节点指针地址
		char* name:姓名(定位)
		int iage:新元素的年龄
		char* iname:新元素的姓名
	返回:
		链表头指针
*/
USER* backInsert(USER* pUser_head, char* name, int iage, char* iname)
{
	USER* p1, *p2; 
	p1=p2= NULL;
	p1 = pUser_head;
	while (p1 != NULL)
	{
		if (p1->name == name)//找到指定节点元素
		{
			break; //结束循环
		}
		else
		{
			p1 = p1->next; //当前节点指针向前移动
		}
	}
	if (p1->next==NULL)//最后一个节点
	{
		USER* pnode = (USER*)malloc(sizeof(USER)); //分配存储空间
		pnode->age = iage;
		pnode->name = iname;
		pnode->next = NULL;//链接为空,它是最后一个节点
		p1->next = pnode; //原来最后节点连接指向新节点
	}
	else//其他节点
	{
		p2 = p1->next; //存储 满足条件节点的下一个节点
		USER* pnode = (USER*)malloc(sizeof(USER)); //分配存储空间
		pnode->age = iage;
		pnode->name = iname;
		pnode->next = p2; //指向满足条件节点的下一个节点
		p1->next = pnode; //满足条件节点的链接指向新节点
	}
	return pUser_head; //头节点没有改变,返回值可有可无。
}


/*
删除链表
	参数:
		USER* pUser_head :头节点指针地址
	返回:
		指针地址为 NULL ,调用时让头指针接受返回值
*/
void* freeAll(USER* pUser_head)
{
	USER* p1, * p2;
	p1 = p2 = NULL;
	p1 = pUser_head;
	while (p1->next!=NULL)
	{
		p2 = p1->next; //指向头节点(p1)的下一个节点
		p1->next = p2->next;  //头节点指向 p2 的下一个节点 ,此时链表跳过了 p2(中间节点) 
		free(p2); //释放 p2
	}
	free(p1); //释放p1 (头节点)
	return NULL;
}

/*
根据年龄删除链表节点元素
	参数:
		USER* pUser_head :头节点指针地址
		int age:年龄
	返回:
		USER* :头节点指针
*/
USER* deleteByAge(USER* pUser_head, int age)
{
	USER* p1, * p2;
	p1 = p2 = NULL;
	p1 = pUser_head;
	while (p1!=NULL)
	{
		if (p1->age == age)
		{
			break; //结束循环
		}
		else
		{
			p2 = p1;//记录当前节点的前一个节点
			p1 = p1->next; //指针向前移动
		}
	}
	if (p1 == pUser_head) //如果头节点满足要求
	{
		pUser_head = p1->next;//改变头节点指针指向第二个节点
		free(p1);
	}
	else //其他节点满足要求
	{
		p2->next = p1->next; //p2 存储了当前满足要求的前一个元素节点,p1 存储了满足要求的节点, 所以,跳过 p1 节点
		free(p1); //释放
	}
	return pUser_head;
}


/*
根据姓名删除链表节点元素
	参数:
		USER* pUser_head :头节点指针地址
		char * name:姓名
	返回:
		USER* :头节点指针
*/
USER* deleteByName(USER* pUser_head, char* name)
{
	USER* p1, * p2;
	p1 = p2 = NULL;
	p1 = pUser_head;
	while (p1 != NULL)
	{
		if (p1->name == name)
		{
			break; //结束循环
		}
		else
		{
			p2 = p1;//记录当前节点的前一个节点
			p1 = p1->next; //指针向前移动
		}
	}
	if (p1 == pUser_head) //如果头节点满足要求
	{
		pUser_head = p1->next;//改变头节点指针指向第二个节点
		free(p1);
	}
	else //其他节点满足要求
	{
		p2->next = p1->next; //p2 存储了当前满足要求的前一个元素节点,p1 存储了满足要求的节点, 所以,跳过 p1 节点
		free(p1); //释放
	}
	return pUser_head;
}

/*
	快速分区
	参数:
		USER* begin :头节点指针地址
		USER* end   :尾节点
	返回:
		 USER* 指针
*/
USER* partition(USER* begin, USER* end)
{
	int key = begin->age; //第一个数据为区分基准数
	//创建双指针
	USER* p1 = begin;      //第一个节点
	USER* p2 = begin->next;//下一个节点

	while (p2!=end)
	{
		if (p2->age < key)
		{
			p1 = p1->next;//循环下一个节点

			//交换符合条件的数据
			int temp_age = p1->age;
			char* temp_name = p1->name;
			p1->age = p2->age;
			p1->name = p2->name;
			p2->age = temp_age;
			p2->name = temp_name;
		}
		p2 = p2->next; //第二指针不断前进
	}

	//交互最后节点
	int temp_age = p1->age;
	char* temp_name = p1->name;
	p1->age = begin->age;
	p1->name = begin->name;
	begin->age = temp_age;
	begin->name = temp_name;

	return p1;
}


/*
	快速排序1(双冒泡), 递归
	参数:
		USER* pUser_head :头节点指针地址
		USER* pUser_back :尾节点(默认 NULL)
	返回:
		 无
*/
void quickSort(USER* pUser_head, USER* pUser_back)
{
	if (pUser_head == NULL || pUser_head->next == NULL || pUser_head == pUser_back)
	{
		return;
	}

	USER* mid = partition(pUser_head, pUser_back);
	quickSort(pUser_head, mid);
	quickSort(mid->next, pUser_back);
}

/*
	快速排序2(双冒泡,指针循环), 递归
	参数:
		USER* begin :头节点指针地址
		USER* end   :尾节点(默认 NULL)
	返回:
		 无
*/
void quickSort2(USER* begin, USER* end)
{
	if (begin == NULL || begin->next == NULL || begin == end)
	{
		return;
	}
	int key = begin->age; //第一个数据为区分基准数
	//创建双指针
	USER* p1 = begin;      //第一个节点
	for (USER* p2 = begin->next; p2 != NULL; p2 = p2->next)
	{
		if (p2->age < key)
		{
			p1 = p1->next;//指针向前

			//交换符合条件的数据
			int temp_age = p1->age;
			char* temp_name = p1->name;
			p1->age = p2->age;
			p1->name = p2->name;
			p2->age = temp_age;
			p2->name = temp_name;
		}
	}

	//交互最后节点
	int temp_age = p1->age;
	char* temp_name = p1->name;
	p1->age = begin->age;
	p1->name = begin->name;
	begin->age = temp_age;
	begin->name = temp_name;

	quickSort2(begin, p1);
	quickSort2(p1->next, end);
}

主函数调用:

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


void main()
{
	struct  UserInfo* user1 = NULL;

	add(&user1, 16, "张三");
	add(&user1, 22, "李四");
	add(&user1, 28, "王五");
	add(&user1, 19, "赵六");
	add(&user1, 13, "田七");
	showAll(user1);
	printf("\n ----------------- \n");

	printf("链表逆转后: \n");
	user1 = reversed(user1); //逆转链表
	showAll(user1);

	printf("\n ----------------- \n");

	printf("链表从大到小排序后: \n");
	sort(user1, '<');
	showAll(user1);
	printf("\n ----------------- \n");

	printf("链表元素个数:%d \n", count(user1));
	printf("\n ----------------- \n");


	printf("分别根据年龄和姓名检索元素: \n");

	USER* u1 = searchOfAge(user1, 19);
	if (u1 != NULL)
	{
		printf("检索年龄为19的节点元素 姓名为:%s ,地址为: %p\n", u1->name, u1);
	}

	USER* u2 = searchOfName(user1, "田七");
	if (u2 != NULL)
	{
		printf("检索姓名是 田七 的节点元素 年龄为:%d ,地址为: %p\n", u2->age, u2);
	}

	printf("\n ----------------- \n");

	printf("插入元素节点: \n");

	user1 = headInsert(user1, 13, 24, "Jom");
	user1 = backInsert(user1, "Jom", 25, "Lily");

	showAll(user1);
	printf("\n ----------------- \n");


	printf("分别根据年龄和姓名修改元素: \n");

	int n1= changeByName(user1, "赵六", "ZhaoLiu");
	if (n1 == 1)
	{
		printf("根据姓名修改元素成功! \n");
	}
	else
	{
		printf("根据姓名修改元素失败! \n");
	}

	int n2 = changeByAge(user1, 13, 130);
	if (n2 == 1)
	{
		printf("根据年龄修改元素成功! \n");
	}
	else
	{
		printf("根据年龄修改元素失败! \n");
	}
	showAll(user1);
	printf("\n ----------------- \n");

	printf("根据年龄或姓名删除链表元素:\n");

	
	user1 = deleteByAge(user1, 28);
	showAll(user1);


	system("pause");

}

输出结果:

 

链表逆转示意图:

 

执行步骤:

NO 1:

NO 2:

NO 3:

 

链表合并:

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



void main()
{
	struct  UserInfo* user1 = NULL;
	struct  UserInfo* user2 = NULL;
	add(&user1, 11, "张三");
	add(&user1, 13, "李四");
	add(&user1, 15, "王五");
	add(&user1, 17, "赵六");
	add(&user1, 19, "田七");
	add(&user1, 20, "嘎嘎");

	add(&user2, 10, "ZhangSan");
	add(&user2, 12, "LiSi");
	add(&user2, 14, "WangWu");
	add(&user2, 16, "ZhaoLiu");
	add(&user2, 18, "TianQi");
	showAll(user1);
	printf("\n ----------------- \n");
	showAll(user2);

	printf("\n --------链表合并--------- \n");

	USER* node = NULL; //从小到大插入合并
	//定义两个 临时指针
	USER* p1 = user1;
	USER* p2 = user2;
	while (p1!=NULL||p2!=NULL)
	{
		if (p1 != NULL && p2 != NULL)
		{
			if (p1->age < p2->age)
			{
				add(&node, p1->age, p1->name);
				//指针向前
				p1 = p1->next;
			}
			else
			{
				add(&node, p2->age, p2->name);
				p2 = p2->next;
			}
		}
		else
		{
			while (p1!=NULL)
			{
				add(&node, p1->age, p1->name);
				//指针向前
				p1 = p1->next;
			}
			while (p2 != NULL)
			{
				add(&node, p2->age, p2->name);
				//指针向前
				p2 = p2->next;
			}
			break;
		}
		
	}

	
	showAll(node);

	printf("\n ----------------- \n");
	system("pause");
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值