【数据结构与算法】线性顺序表原理及C语言实现

参考博文:程序内功篇二–线性顺序表

一、线性表顺序存储概念

  • 线性表示包含若干个数据元素的一个线性序列,记为:L=(a0,a1, … ai-1,ai,ai+1,…an-1),其中L为表名, ai为数据元素, n为表长
  • 若将线性表L=(a0,a1, …,an-1)中的各元素依次存储于计算机一片连续的存储空间。

线性表的特征:

  • 对非空表,a0 是表头,无前驱
  • an-1是表尾,无后继
  • 其他的每个元素 ai 有且仅有一个直接前驱 ai-1,和一个直接后继 ai+1

顺序存储结构的特点:

  • 逻辑上相邻的元素ai,ai+1,其存储位置也是相邻的
  • 对数据元素ai的存取为随机存取或按地址存取
  • 存储密度高

存储密度D=(数据结构中元素所占存储空间)/(整个数据结构所占空间)

顺序存储结构的表示:
在C语言中,可借助于结构体配合一维数组类型来描述线性表的顺序存储结构:

//变量与顺序表结构定义
#define N 100
typedef int data_t;

typedef struct{
	data_t data[N];	//表的存储空间
	int n;			//线性表中最后一个元素下标
}sqlist;

注意: n表示线性表最后一个元素的下标

二、顺序表的基本属性程序设计

(1)线性表的创建 list_create

 线性表的创建主要分为申请内存空间、初始化变量、返回顺序表指针三大步骤。

  • 功能:建立一个空的线性表
  • 参数:void
  • 返回值:线性表指针
    /*
    功能:建立一个空的线性表
    参数:void
    返回值:线性表指针
    */
    sqlist* list_create()
    {
    	//申请内存空间
    	sqlist* list = (sqlist *)malloc(sizeof(sqlist));
    	if(list == NULL){
    		printf("list_create: malloc error\n");
    		return NULL;
    	}
    	
    	//线性表成员变量赋值
    	list->n = -1;
    	
    	return list;
    }
    

(2)清空顺序表 list_clear

 清空顺序表主要对顺序表内部数据进行初始化,对结尾数据下标索引置-1:

  • 功能:清空线性表
  • 参数:线性表指针
  • 返回值:-1:参数错误   成功:0
    /*
    功能:清空线性表
    参数:线性表指针
    返回值:-1---参数错误   成功返回 0
    */
    int list_clear(sqlist* list)
    {
    	//入口 参数检查
    	if(list == NULL){
    		printf("list_clear: list is NULL");
    		return -1;
    	}
    	
    	//清空数组数据
    	int len = list_length(list);
    	memset(list->data, '\0', sizeof(data_t) * len);
    	list->n = -1;
    	
    	return 0;
    }
    

(3)判断是否为空表 list_empty

 判断顺序表是否为空表的关键是:判断结尾数据的索引是否为-1

  • 功能:判断线性表是否为空
  • 参数:线性表指针
  • 返回值:空:1   非空:0
    /*
    功能:判断线性表是否为空
    参数:线性表指针
    返回值:空:返回1  非空: 返回0
    */
    int list_empty(sqlist* list)
    {
    	if(list->n == -1)
    		return 1;
    	else
    		return 0;
    }
    

(4)获取线性表长度 list_length

 线性表的长度即是 最后一个元素索引+1

  • 功能:求线性表长度
  • 参数:线性表指针
    返回值:-1:参数错误  >0: 表长
    /*
    功能:求线性表长度
    参数:线性表指针
    返回值:-1---参数错误   >0 表长
    */
    int list_length(sqlist* list)
    {
    	//入口 参数检查
    	if(list == NULL){
    		printf("list_length: list is NULL");
    		return -1;
    	}
    	
    	//返回线性表长度
    	return list->n + 1;
    }
    

(5)显示线性表 list_show

 通过遍历线性表内连续空间实现对线性表的呈现

  • 功能:显示线性表
  • 参数:线性表指针
  • 返回值:void
    /*
    功能:显示线性表
    参数:线性表指针
    返回值:void
    */
    void list_show(sqlist* list)
    {
    	if(list->n == -1)
    		printf("list is NULL");
    	if(list != NULL)
    	{
    		for(int i = 0; i <= list->n; i++)
    			printf("%d ",list->data[i]);
    		printf("\n");
    	}
    	else
    		printf("list is NULL\n");
    }
    

(6)释放线性表内存空间 list_free

 通过遍历线性表实现内存的释放

  • 功能:释放线性表内存空间
  • 参数:线性表指针
  • 返回值:-1: 参数错误/为空  0:释放成功
    /*
    功能:释放线性表内存表空间
    参数:线性表指针
    返回值:-1: 参数错误/为空  0: 释放成
    */
    int list_free(sqlist* list)
    {
    	//入口参数检查
    	if(list == NULL)
    		return -1;
    	free(list);		//释放内存
    	list = NULL;	//避免成为野指针
    	return 0;	
    }
    

三、顺序表的相关运算程序设计

(1)获取线性表元素 getVal

 通过下标获取对应下标索引的值

  • 功能:根据下标获取某个元素
  • 参数:线性表指针
  • 返回值:-1: 参数错误/为空, 正常返回获取的元素
    /*
    功能:根据下标获取某个元素
    参数:线性表指针
    返回值:-1: 参数错误/为空  正常返回获取的元素
    */
    data_t list_getVal(sqlist* list, int index) //获取ai的值
    {
    	//入口 参数检查
    	if(list == NULL)
    		printf("list_getVal: list is NULL");
    	
    	return list->data[index];
    }
    

(2)定位线性表元素的下标 list_locate

 获取某个元素在线性表内的下标索引,同时可通过下标判断某个元素是否在线性表内(返回 -1 表示该元素不在表内)

  • 功能:获取某元素在线性表的下标
  • 参数:para1: 线性表指针, para2: 需要定位的元素值
  • 返回值:返回value在表中的下标, 不存在则返回-1
    /*
    功能:定位运算
    参数:线性表指针, 需要定位的元素值
    返回值:返回value在表中的下标, 不存在则返回-1
    */
    int list_locate(sqlist* list, data_t value)	//确定元素value在表中的下标
    {
    	if(list == NULL)
    		return -1;
    	
    	//比较value是否在 list内
    	for(int i = 0; i <= list->n; i++)
    	{
    		if(list->data[i] == value)
    			return i;
    	}
    	return -1;
    }
    

(3)线性表插入元素(头插+尾插+任意位置)

1. 头插法插入数据 list_push_front

 头插法插入数据在入口参数判断后:
 ①首先将所有数据往后移动1位
 ②接着将需要插入的数据存入线性表第一位
 ③记得线性表长度+1

  • 功能:头插法插入元素
  • 参数:para1:线性表指针  para2:待插入的元素
  • 返回值:-1: 参数错误  0: 插入成功
    /*
    功能:头插法插入元素
    参数:para1:线性表指针  para2:待插入的元素
    返回值:-1: 参数错误  0: 插入成功
    */
    int list_push_front(sqlist* list, data_t value)
    {
    	//入口参数检查
    	if(list == NULL || list->n >= N-1){
    		printf("push_front para error\n");
    		return -1;
    	}
    	
    	//右移 
    	list->n++;	//线性长+1
    	for(int i = list->n; i > 0; i--)
    		list->data[i] = list->data[i-1];
    	
    	//插入新数据
    	list->data[0] = value;
    	return 0;
    }
    
    头插法插入数据需要遍历移动整个线性表,因此插入数据的效率较低。

2. 尾插法插入数据 list_push_back

 尾插法只需表长+1,在线性表尾插入元素即可:

  • 功能:尾插法插入元素
  • 参数:para1:线性表指针  para2:待插入的元素
  • 返回值:-1: 参数错误  0: 插入成功
    /*
    功能:尾插法插入元素 
    参数:para1:线性表指针	para2:待插入的元素
    返回值:-1: 参数错误  0: 插入成功
    */
    int list_push_back(sqlist* list, data_t value)
    {
    	//入口参数检查
    	if(list == NULL || list->n >= N-1){
    		printf("push_back para error\n");
    		return -1;
    	}
    	
    	//线性表尾插入数据
    	list->n++;
    	list->data[list->n] = value;	
    	return 0;
    }
    
    尾插法插入数据直接在表尾插入即可,因此效率较高。

3. 任意位置插入数据 list_insert

 在任意位置插入元素需要判断线性表是否为空或已满,插入位置是否合法若插入位置大于表长,则在表尾插入,使线性表空间有序。
 若在合法位置插入数据,需要将插入位置后续的数据往后移1位,空出目标位置插入新的数据,同时线性表长度将+1

  • 功能:特定位置插入元素
  • 参数:para1:线性表指针 para2:待插入的元素
  • 返回值:-1:参数错误  0:插入成功
/*
功能:特定位置插入元素
参数:para1:线性表指针&emsp;&emsp;para2:待插入的元素
返回值:-1:参数错误  0: 插入成功
*/
int list_insert(sqlist* list, int index, data_t value)
{
	//入口参数检查
	if(list == NULL){
		printf("list_insert para error\n");
		return -1;
	}
	//插入位置有误
	if(index < 0 || list->n >= N-1){
		printf("index index error\n");
		return -1;
	}
	
	//插入位置大,放表尾
	else if(index > list->n){
		list->n++;
		list->data[list->n] = value;	
		return 0;
	}
	else
	{
		list->n++;	//表长+1
		//右边数据后移 从后往前
		for(int i = list->n; i > index; i--)	
			list->data[i] = list->data[i-1];
		//插入数据
		list->data[index] = value;
		return 0;
	}
}

(4)根据索引删除元素 list_delete

 在删除元素之前先判断线性表是否为空,传入的删除下标位置是否合法,删除操作只需将目标位置后面的数据往前移1位即可

  • 功能:删除索引为index的元素
  • 参数:para1:线性表指针, para2:待删除的下标位置
  • 返回值:-1: 参数错误  0: 删除成功
/*
功能:删除索引为index的元素
参数:para1:线性表指针, para2:待删除的下标位置
返回值:-1: 参数错误  0: 删除成功
*/
int list_delete(sqlist* list, int index)
{
	//入口参数检查: 表空 / 删除索引非法
	if(list == NULL || list->n == -1 || index < 0 || index > list->n ){
		printf("list_delete para error\n");
		return -1;
	}
	
	//数据左移 覆盖即删除
	for(int i = index; i < list->n; i++){
		list->data[i] = list->data[i+1];
	}
	
	//线性表长度减1
	list->n--;	
	return 0;
}

(5)线性表的合并 list_merge

 线性表的合并即将list2中的元素合并至list1,如果list1中存在list2中的元素不并入,否则将list2的数据加入list1

  • 功能:线性表合并, list2并入list1
  • 参数:参数1:线性表1指针 参数2: 线性表2指针
  • 返回值:–1: 参数错误  0: 合并成功

  程序设计思路:通过遍历list2中的元素,判断list2中的每个元素是否在list1中出现过(list_locate)。若出现过则丢弃,若没有出现过,则尾插进list1(list_push_back)

/*
功能:线性表合并 list2并入list1
参数:参数1:线性表1指针 参数2: 线性表2指针
返回值:--1: 参数错误  0: 合并成功
*/
int list_merge(sqlist* list1, sqlist* list2)
{
	//入口参数错误
	if(list1 == NULL || list2 == NULL)
		return -1;
	
	for(int i = 0; i <= list2->n; i++)
	{
		int ret = list_locate(list1, list2->data[i]);
		//找到list2中有元素不在list1,尾插数据
		if(ret == -1){
			list_push_back(list1, list2->data[i]);	
		}		
	}
	return 0;
}

(5)线性表的去重 list_purge

 线性表的去重即去除表内的重复元素
程序设计思路: 依次遍历a1…an元素ai,判断ai是否在[a0,ai-1]内出现过,若出现过则删除ai,重新比较ai,若没有出现过,则进行下一轮判断。

  • 功能:删除线性表中重复元素
  • 参数:线性表指针指针
  • 返回值:-1: 参数错误   0: 删除成功
/*
功能:删除线性表中重复元素
参数:线性表指针
返回值:-1: 参数错误  	0: 删除成功
*/
//依次取i [1,n],判断ai是否在[0,ai-1]内
//若不在,i++,若在,删除ai,重新比ai
int list_purge(sqlist* list)
{
	//入口参数检查
	if(list == NULL){
		printf("list_purge: list error\n");
		return -1;
	}
	
	//只有1个数
	if(list->n == 0)
		return 0;
		
	int i = 1;
	//开始遍历 i [1,n]的元素
	while(i <= list->n)
	{
		int j = i-1;
		//开始遍历 [0,ai-1]元素
		while(j >= 0)
		{
			if(list->data[i] == list->data[j])
			{
				list_delete(list, i);
				break;
			}	
			else
				j--;	
		}
		
		//没找到 
		if(j < 0)
			i++;
	}
	return 0;
}

附件:测试程序及源程序

线性表插入与删除测试程序:

//线性表插入与删除测试
void test_inert_delete()
{
	sqlist* list = list_create();
	if(list == NULL){
		printf("list create error\n");
		return;
	}
	
	//头插 尾插 中间插 并显示
	list_push_back(list, 66);
	list_push_back(list, 100);
	list_push_back(list, 22);
	list_push_front(list,12);
	list_insert(list,3,76);
	list_show(list);
	
	//删除数据并显示
	list_delete(list,2);
	list_show(list);
	
	//释放表
	list_free(list);
}

线性表合并测试函数:

void test_merge()
{
	//创建线性表1
	sqlist* list1 = list_create();
	list_push_back(list1,10);
	list_push_back(list1,20);
	list_push_back(list1,30);
	
	//创建线性表2
	sqlist* list2 = list_create();
	list_push_back(list2,30);
	list_push_back(list2,50);
	
	//将表2合并至表1
	list_merge(list1,list2);
	list_show(list1);
	
	list_free(list1);
	list_free(list2);
}

测试删除重复元素:

void test_purge()
{
	//创建线性表1
	sqlist* list = list_create();
	list_push_back(list,10);
	list_push_back(list,10);
	list_push_back(list,10);
	list_push_back(list,10);
	list_push_back(list,10);
	list_push_back(list,10);
	
	list_show(list);
	list_purge(list);
	list_show(list);
	list_free(list);
}

sqlist.c:

#include "sqlist.h"

/********************函数实现*******************/
/*
功能:建立一个空的线性表
参数:void
返回值:线性表指针
*/
sqlist* list_create()
{
	//申请内存空间
	sqlist* list = (sqlist *)malloc(sizeof(sqlist));
	if(list == NULL){
		printf("list_create: malloc error\n");
		return NULL;
	}
	
	//线性表成员变量赋值
	list->n = -1;
	
	return list;
}

/*
功能:清空线性表
参数:线性表指针
返回值:-1---参数错误   成功返回 0
*/
int list_clear(sqlist* list)
{
	//入口 参数检查
	if(list == NULL){
		printf("list_clear: list is NULL");
		return -1;
	}
	
	//清空数组数据
	int len = list_length(list);
	memset(list->data, '\0', sizeof(data_t) * len);
	list->n = -1;
	
	return 0;
}

/*
功能:判断线性表是否为空
参数:线性表指针
返回值:空:返回1  非空: 返回0
*/
int list_empty(sqlist* list)
{
	if(list->n == -1)
		return 1;
	else
		return 0;
}

/*
功能:求线性表长度
参数:线性表指针
返回值:-1---参数错误   >0 表长
*/
int list_length(sqlist* list)
{
	//入口 参数检查
	if(list == NULL){
		printf("list_length: list is NULL");
		return -1;
	}
	
	//返回线性表长度
	return list->n + 1;
}



/*
功能:显示线性表
参数:线性表指针
返回值:void
*/
void list_show(sqlist* list)
{
	if(list->n == -1)
		printf("list is NULL");
	if(list != NULL)
	{
		for(int i = 0; i <= list->n; i++)
			printf("%d ",list->data[i]);
		printf("\n");
	}
	else
		printf("list is NULL\n");

}

/*
功能:释放线性表内存表空间
参数:线性表指针
返回值:-1: 参数错误/为空  0: 释放成
*/
int list_free(sqlist* list)
{
	if(list == NULL)
		return -1;
	free(list);
	list = NULL;
	return 0;	
}


/*
功能:根据下标获取某个元素
参数:线性表指针
返回值:-1: 参数错误/为空  正常返回获取的元素
*/
data_t list_getVal(sqlist* list, int index) //获取ai的值
{
	//入口 参数检查
	if(list == NULL)
		printf("list_getVal: list is NULL");
	
	return list->data[index];
}

/*
功能:定位运算
参数:线性表指针, 需要定位的元素值
返回值:返回value在表中的下标, 不存在则返回-1
*/
int list_locate(sqlist* list, data_t value)	//确定元素value在表中的下标
{
	if(list == NULL)
		return -1;
	
	//比较value是否在 list内
	for(int i = 0; i <= list->n; i++)
	{
		if(list->data[i] == value)
			return i;
	}
	return -1;
}

/*
功能:尾插法插入元素
参数:para1:线性表指针	para2:待插入的元素
返回值:-1: 参数错误  0: 插入成功
*/
int list_push_back(sqlist* list, data_t value)
{
	//入口参数检查
	if(list == NULL || list->n >= N-1){
		printf("push_back para error\n");
		return -1;
	}
	
	//线性表尾插入数据
	list->n++;
	list->data[list->n] = value;	
	return 0;
}

/*
功能:头插法插入元素
参数:para1:线性表指针	para2:待插入的元素
返回值:-1: 参数错误  0: 插入成功
*/
int list_push_front(sqlist* list, data_t value)
{
	//入口参数检查
	if(list == NULL || list->n >= N-1){
		printf("push_front para error\n");
		return -1;
	}
	
	//右移 
	list->n++;	//线性长+1
	for(int i = list->n; i > 0; i--)
		list->data[i] = list->data[i-1];
	
	//插入新数据
	list->data[0] = value;
	return 0;
}


/*
功能:特定位置插入元素
参数:para1:线性表指针	para2:待插入的元素
返回值:-1:参数错误  0: 插入成功
*/
int list_insert(sqlist* list, int index, data_t value)
{
	//入口参数检查
	if(list == NULL  || list->n >= N-1){
		printf("list_insert para error\n");
		return -1;
	}
	//线性表满了
	if(index < 0 || index > N){
		printf("index index error\n");
		return -1;
	}
	
	//插入位置大,放表尾
	else if(index > list->n){
		list->n++;
		list->data[list->n] = value;	
		return 0;
	}
	else
	{
		list->n++;	//表长+1
		//右边数据后移 从后往前
		for(int i = list->n; i > index; i--)	
			list->data[i] = list->data[i-1];
		//插入数据
		list->data[index] = value;
		return 0;
	}
}



/*
功能:删除索引为index的元素
参数:para1:线性表指针, para2:待删除的下标位置
返回值:-1: 参数错误  0: 删除成功
*/
int list_delete(sqlist* list, int index)
{
	//入口参数检查: 表空 / 删除索引非法
	if(list == NULL || list->n == -1 || index < 0 || index > list->n ){
		printf("list_delete para error\n");
		return -1;
	}
	
	//数据左移 覆盖即删除
	for(int i = index; i < list->n; i++){
		list->data[i] = list->data[i+1];
	}
	
	//线性表长度减1
	list->n--;	
	return 0;
}

/*
功能:线性表合并 list2并入list1
参数:参数1:线性表1指针 参数2: 线性表2指针
返回值:--1: 参数错误  0: 合并成功
*/
int list_merge(sqlist* list1, sqlist* list2)
{
	//入口参数错误
	if(list1 == NULL || list2 == NULL)
		return -1;
	
	for(int i = 0; i <= list2->n; i++)
	{
		int ret = list_locate(list1, list2->data[i]);
		//找到list2中有元素不在list1,尾插数据
		if(ret == -1){
			list_push_back(list1, list2->data[i]);	
		}		
	}
	return 0;
}

/*
功能:删除线性表中重复元素
参数:线性表指针
返回值:-1: 参数错误  	0: 删除成功
*/
//依次取i [1,n],判断ai是否在[0,ai-1]内
//若不在,i++,若在,删除ai,重新比ai
int list_purge(sqlist* list)
{
	//入口参数检查
	if(list == NULL){
		printf("list_purge: list error\n");
		return -1;
	}
	
	//只有1个数
	if(list->n == 0)
		return 0;
		
	int i = 1;
	//开始遍历 i [1,n]的元素
	while(i <= list->n)
	{
		int j = i-1;
		//开始遍历 [0,ai-1]元素
		while(j >= 0)
		{
			if(list->data[i] == list->data[j])
			{
				list_delete(list, i);
				break;
			}	
			else
				j--;	
		}
		
		//没找到 
		if(j < 0)
			i++;
	}
	return 0;
}

sqlist.h

#ifndef __SQLIST__H
#define __SQLIST__H

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

//变量与顺序表结构定义
#define N 100
typedef int data_t;

typedef struct{
	data_t data[N];	//表的存储空间
	int n;			//线性表中最后一个元素下标
}sqlist;

/*****************函数声明*******************/
/*************顺序表的基本属性***************/
sqlist* list_create(int n);		//建立一个空表
int list_clear(sqlist* list);	//清空表
int list_empty(sqlist* list);	//判断表是否为空
int list_length(sqlist* list);	//求线性表长度
void list_show(sqlist* list);	//显示线性表
int list_free(sqlist* list);	//释放线性表空间

/*************顺序表的相关运算***************/
data_t list_getVal(sqlist* list, int pos); 				//根据索引获取值
int list_locate(sqlist* list, data_t value);			//确定元素value的索引值
int list_push_back(sqlist* list, data_t value);			//尾插法
int list_push_front(sqlist* list, data_t value);		//头插法
int list_insert(sqlist* list, int pos, data_t value);	//在特定位置插入元素
int list_delete(sqlist* list, int index);				//删除一个元素
int list_merge(sqlist* list1, sqlist* list2);			//线性表合并 list2并入list1
int list_purge(sqlist* list1);							//删除线性表中重复元素

#endif
  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
数据结构和算法是计算机科学中非常重要的概念。数据结构是为解决实际问题而设计的,用于存储和组织数据的方式。它可以分为逻辑结构和物理结构。逻辑结构包括集合结构、线性结构、树形结构和图形结构,而物理结构则包括顺序存储和链式存储。 算法则是解决问题的一系列步骤或操作。它具有输入、输出、有穷性、确定性和可行性这五个基本特性。算法是在数据结构上操作的过程,通过对数据结构的操作实现问题的解决。 在C语言中,我们可以使用不同的数据结构和算法来解决问题。例如,队列是一种常用的数据结构,它可以使用链表来实现,其中包括头结点和尾结点。队列可以进行插入和删除操作,通常使用头尾指针来指示队列的状态。循环队列是一种特殊的队列,当队列满时,头指针会指向尾指针的下一个位置,而当队列为空时,头指针和尾指针指向同一个位置。 另一个常用的数据结构是栈,它具有先进后出的特性。栈的应用包括前缀、中缀和后缀表达式的计算。在这些表达式中,运算符的优先级决定了计算的顺序。前缀表达式将运算符放在操作数之前,后缀表达式将运算符放在操作数之后,而中缀表达式则是我们日常生活中最常见的形式。 综上所述,数据结构和算法是C语言中解决问题的重要工具。我们可以根据问题的特点选择合适的数据结构和算法来实现解决方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [数据结构和算法(C语言)](https://blog.csdn.net/weixin_60096751/article/details/123643490)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [C语言数据结构与算法](https://blog.csdn.net/Syext/article/details/129896715)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会编程的小江江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值