C语言---深入指针(4)

回调函数

//回调函数就是通过函数指针调用的函数
//这个在之前的转移表-计算器里面很明显,通过函数指针数组内的函数指针进行函数的调用
//
// 
// 将这四段代码分装成一个函数,一个代码将这4个问题都解决
int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mull(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}
void menu()
{printf("**************************************\n");printf("**********   1.add    2.sub***********\n");printf("*********    3.mull   4.div***********\n");printf("*********    0.exit      *************\n");printf("**************************************\n");
}
void Calc(int (*pf)(int, int))//因为传过来的是函数的地址,那么就要用函数指针进行接收
{int x = 0, y = 0,ret=0;printf("请输入两个操作数");scanf("%d %d", &x, &y);ret = pf(x, y);//当pf接收到的是加法函数的地址的时候,我们直接用pf来调用//对于函数名就是函数的地址,用指针变量存起来的就是函数地址,那么指针变量的名字就是函数变量的地址//那么可以直接用指针变量的名字进行调用printf("%d\n", ret);
}
int main()
{int ret = 0;int input = 0;int x = 0, y = 0;do{menu();//菜单printf("请选择:");scanf("%d", &input);switch (input){case 1:Calc(Add);    //将加法函数的地址传过去--函数名是地址       break;case 2:Calc(Sub);            break;case 3:Calc(Mull);            break;case 4:Calc(Div);break;case 0:printf("退出计算器\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}//这4个代码的差异就是运算的方式不同
//
// Calc是中间商,Add这些计算的函数是回调函数
// 
// 通过函数调用另一个函数进行调用
//
//当你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其
//所指向的函数时,被调用的函数就是回调函数
//这个代码里面回调函数就是Add,Sub,Mull,Div

回忆冒泡函数

//回忆冒泡排序---对一组整数进行排序
//void bubble_sort(int arr[], int sz)//接受一个整型数组
//{
//    //趟数
//    for (int i = 0; i < sz-1; i++)
//    {
//        //一趟内部的两两比较
//        for (int j = 0; j < sz - 1 - i; j++)
//        {
//            if (arr[j] > arr[j + 1])
//            {
//                int tmp = arr[j];
//                arr[j] = arr[j + 1];
//                arr[j + 1] = tmp;
//            }
//        }
//    }
//}
//print(int arr[], int sz)
//{
//    for (int i = 0; i < sz; i++)
//    {
//        printf("%d ", arr[i]);
//    }
//}
//int main()
//{
//    int arr[] = { 3,1,7,9,4,2,6,8,0 };
//    //进行排序--升序
//    int sz = sizeof(arr) / sizeof(arr[0]);
//
//    //冒泡排序核心思想,两两数字进行比较,不满足我们要求的顺序的话我们可以对其进行交换
//    //满足我们要求的顺序的话我们就换下一对数字进行比较
//    
//    //冒泡排序进行排序
//    bubble_sort(arr,sz);
//    print(arr,sz);
//    return 0;
//}
//对于冒泡排序的话,只能排序整型数组
//对于其他类型的数组无法排序
//字符串数组、字符数组、结构体数组、浮点数数组

strcmp----字符串的大小比较

/字符串的比较
//应该使用strcmp进行比较
//int strcmp(const char* str1, const char* str2);
//char str1[]="Hello";
//char str2[]="hello";
//strcmp(str1, str2));
// 如果 strcmp 返回值大于 0,
// 则表示第一个字符串(str1)在比较中大于第二个字符串(str2)。
// 

a,b,c,d,c,e,f

a,b,c,q

因为d的ASCII小于q的,所以第一行的字符串就小于第二行的字符串

strcmp比较的不是长度,比较的是对应位置的字符ASCII大小的

qsort的结构

而接下来介绍的qsort能适用于任意类型的数据的排序
void qsort(void* base,//指向待排序数组第一个元素的指针size_t num, //base指向的数组中的元素个数size_t size, //base指向的数组中每个元素的大小int(*com)(const void*, const void*)//函数指针--传递函数的地址//);

利用qsprt进行整型数组的排序

//对于冒泡排序比较不同的类型的数据时,两个循环没有什么差异,但是对于不同的数据进行比较就有着差异
//对于整数是进行比较大小,但是并不是所有的数据能能用比'>''<'进行比较//既然不同数据的元素比较是有差异的,那么就直接把两个元素比较的代码抽离出来 
//谁要调用qsort来进行比较排序,那就让谁提供比较的函数//下面的函数比较的是p1指向的元素和p2指向的元素
//对函数
//p1指向的元素比p2指向的元素小的时候,返回的是小于0的数
//p1指向的元素等于p2指向的元素的时候,返回的是0
//p1指向的元素比p2指向的元素打的时候,返回的是大于0的数//咱么为了使用qsort函数,我们必须提供一个比较2个整型的比较函数
//格式int cmp_int(const void*p1, const void*p2),那么这个函数的名字就是qsort函数的第四个条件
//int cmp_int(const void*p1, const void*p2)
//{
//    //p1就指向了这个数组里面的3,p2指向的就是1
//    /*if(*p1>*p2)*///不能这么写,因为在函数的参数里面,p1的类型是void*,p2是void*
//    //void *指针不能进行解引用操作
//    //将p1的类型强制转换成int*,再进行解引用就行了     *(int*)p1
//    //比较的三种情况
//    if (*(int*)p1 > *(int*)p2)
//    {
//        return 1;
//    }
//    else if (*(int*)p1 < *(int*)p2)
//    {
//        return -1;
//    }
//    else
//    {
//        return 0;
//    }
//
//}
//void print(int arr[], int sz)
//{
//    for (int i = 0; i < sz; i++)
//    {
//        printf("%d ", arr[i]);
//    }
//}
test这个函数测试qsort来排序整型数据
//void test1()
//{
//    int arr[] = { 3,1,7,9,4,2,6,8,0 };
//    int sz = sizeof(arr) / sizeof(arr[0]);
//    qsort(arr, sz, sizeof(arr[0]), cmp_int);
//    //(数组首元素地址,数组长度,每个元素字节大小,进行比较大小的函数)
//    print(arr, sz);//打印排序完后的数组
//}
//int main()
//{
//    test1();
//    return 0;
//}//提供想要排序的数组,计算数组元素个数
//再利用qsort进行排序
//再利用qsort进行排序的时候,要提供数组首元素的地址、数组长度、数组每个元素的字节大小、
//最后再提供一个比较的函数的函数名,这个函数有固定的写法
//int cmp_int(const void*p1, const void*p2)
//因为p1和p2的类型都是void*,不能对其进行解引用进行比较,
//所以我们必须将其强制类型转换,(int*)p1
//再对其进行解引用*(int*)p1
//再将*(int*)p1与*(int*)p2进行比较
//前者大于后者就返回大于0的数
//前者小于后者就返回小于0的数
//前者等于后者就返回0//对于qsort函数来说,我们只需要额外构建一个比较函数就能利用qsort进行快速排列

对于qsort函数来说,我们只需要额外构建一个比较函数就能利用qsort进行快速排列

//对下面代码进行简化
// test1
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
//因为这里比较的是整数,那么我们直接作差返回
void print(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
//test这个函数测试qsort来排序整型数据
void test1()
{int arr[] = { 3,1,7,9,4,2,6,8,0 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_int);//(数组首元素地址,数组长度,每个元素字节大小,进行比较大小的函数)print(arr, sz);//打印排序完后的数组
}
int main()
{test1();return 0;
}

利用qsprt进行结构体的排序

/*void qsort(void* base,//指向待排序数组第一个元素的指针size_t num, //base指向的数组中的元素个数size_t size, //base指向的数组中每个元素的大小int(*com)(const void*, const void*)//函数指针--传递函数的地址//);*/
//利用qsort函数对结构体进行排序
struct Stu//创建一个结构体
{char name[20];int age;
};//按照名字比较两个结构体的数据
int cmp_stu_by_name(const void* p1, const void* p2)//p1和p2分别指向数组中的结构体
{//先将p1强制类型转换//(struct Stu*)p1---结构体指针-----不能直接指向成员  错误写法:(struct Stu*)p1->//要先括起来,将强制类型转换后的结构阔起来,才能找到成员//((struct Stu*)p1)->name, ((struct Stu*)p2)->name// //两个名字是字符串,字符串比较是采用strcmp函数的return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);//因为strcmp函数的返回值和我们期望的qsort的第四个比较函数的返回值一样的,//所以我们直接将strcmp的值返回//strcmp要包含头文件的include <string.h>
}
void print(struct Stu arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%s ", arr[i].name);}
}
void test2()
{struct Stu arr[] = { {"zhangsan",20},{"lisi",35},{"wangwu",18}};//给了三个人的信息 //利用qsort对数组内的信息进行排序int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);//传递的函数是进行比较两个结构体对象//但是我们现在是按照名字比较还是年龄比较呢?print(arr, sz);
}int main()
{test2();return 0;
}
//按照年龄排序
struct Stu//创建一个结构体
{char name[20];int age;
};
void print(struct Stu arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i].age);}
}//打印结果:18 20 35
void cmp_stu_by_age(const void* p1, const void* p2)
{//return strcmp(((struct Stu*)p1)->age, ((struct Stu*)p2)->age);//因为age是两个整数,所以不需要用strcmp了return ((struct Stu*)p1)->age-((struct Stu*)p2)->age;//将他们的值进行大小比较,直接返回//前者大于后者直接返回大于0的数//前者小于后者直接返回小于0的数//前者等于后者直接返回0}
void test3()
{struct Stu arr[] = { {"zhangsan",20},{"lisi",35},{"wangwu",18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);print(arr, sz);}
int main()
{test3();return 0;
}

关于结构体的补充知识点

利用结构体指针来访问结构体里面的成员对象

//结构体知识点补充,利用结构体指针来找到结构体里面的数据
struct Stu//创建一个结构体
{char name[20];int age;
};
int main()
{struct Stu s = { "zhangsan",20 };//第一种写法:printf("%s %d\n", s.name, s.age);//这里的知识点就是利用结构体名字加点再加结构体对象,就可以调用出对应的数struct Stu* ps=&s;//将变量s的地址取出存放到结构体指针内//struct Stu*就是这个结构体指针ps的类型//ps里面存放的是s的地址,ps就指向了s//第二种写法://那么我们利用ps来找到这个结构体数组里面的数据怎么找呢?printf("%s %d\n", (*ps).name, (*ps).age);
//ps是里面存放的是这个结构体的地址,对ps进行解引用得到的就是这个结构体s了//第三种写法:printf("%s %d\n", ps->name, ps->age);//ps指向的对象的成员return 0;
}
//结构体成员访问操作符
// .       结构体变量.成员名
//->       结构体指针->成员名

qsort函数的总结

对于qsort函数来说

主要的就是括号内的第四个元素,也就是进行元素比较的函数的名字

对于qsort来说,这个进行比较的函数只需要返回三种值

大于0,小于0,或者等于0,只要传递回来就能直接快速排列

对于qsort函数来说:

第一个元素是要排列的数组的首元素的地址,就是数组名

第二个元素就是这个数组的元素个数sz

第三个元素就是每个元素的字节大小sizeof([0])

第四个元素就是这个比较的函数的函数名

对于这个比较函数就有说法了

这个就是固定格式

返回值是数字,就是大于0的数,0,小于0的数,所以函数前面是int

int cmp_int(const void* p1, const void* p2)

p1和p2的类型都是void*

p1和p2都指向的数组内的要进行比较的元素

如果要进行比较的话就需要对这个指针进行强制类型转换

假设:

int*强制类型转换,

(int*)p1

再对转换后的结果进行解引用就是p1指向的那个数

(int)p1

判断的是整型数组的话:

那么我们直接写:return* (int*)p1 - *(int*)p2;

两个数进行相减,返回值三种情况:大于0的数、0、小于0的数

假如说要判断结构体成员的年龄的话

return ((struct Stu)p1)->age-((struct Stu)p2)->age;

返回的就是年龄相减的值

先强制类型转换p1

(struct Stu*)p1

因为p1指向的是这个结构体数组,那么我们直接通过箭头操作符直接访问数据

(struct Stu*)p1→age

假如说要判断结构体成员的姓名的话

对于这个结构体数组来说,这个姓名就是字符串

对于字符串的比较我们要用到strcmp函数

因为我们想要的这个比较函数的返回值和这个strcmp的返回值一样的,那么我们直接返回strcm函数的值

return strcmp(((struct Stu)p1)->name, ((struct Stu)p2)->name);

strcmp(((struct Stu)p1)->name, ((struct Stu)p2)->name)

在strcmp函数中进行比较的是((struct Stu)p1)->name和((struct Stu)p2)->name

qsort实现升序和降序的原理

因为qsort默认实现的是升序

对于数组的快排,如果我们想实现数组的降序,

因为qsort是固定死的

但是qsort里面的一个元素,第四个元素,比较函数

我们只能通过这个比较函数来实现降序

对于这个代码

return ((struct Stu)p1)->age-((struct Stu)p2)->age;

如果前者大于后者就返回大于0的数,如果是升序的话,那么就要将这个较大的数和这个较小的数进行交换,因为我们要实现升序的效果,就是从小到大

如果想实现降序的话,我们将逻辑反过来:

return ((struct Stu)p2)->age-((struct Stu)p1)->age;

后面的大于前面的,返回值是小于0的数,因为要实现降序,那么我们就将较大的数与较小的数进行交换

咱们仔细想想,

对于qsort函数来讲,我们交换数组元素的条件是啥呢?

就是这个返回的值

如果我们写的是前面的值减去后面的值大于0的话就进行交换,就是前面的数大于后面的数,把大的换后面去,所以这种写法代表的排序顺序就是升序

假如后面的值大一些呢,就是前面值减去后面的值小于0,就是说后面的大,前面的小,就将这两个数进行交换,那么大的值都在前面,小的值在后面,那么我们就实现了降序了

就是对于qsort来说,我们这个快速排列需要交换满足条件的值,那么这个比较函数里面的条件就是这个满足交换条件的值交换的条件,就是return 后面的条件,如果这个返回值大于0的话就将这两个数进行对调了

p1-p2>0我们就对调这两个数----大的换后面去,---升序

p2-p1>0我们就对调这两个数----大的换前面去----降序

qsort函数的模拟实现

//我们是否能将bubble_sort函数改造成通用的算法,可以排序任意类型的数据
//模仿qsort
struct stu
{char name[20];int age;
};
int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);
}int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
int cmp_stu_by_age(const void* p1, const void* p2)
{return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}void Swap(char* buf1, char* buf2, size_t width)//传过来的是hcar*指针,那么我们就用char*接受
{char tmp = 0;for (int i = 0; i < width; i++)//因为不知道两个元素之间有多少个字节,那么我们就把每个字节进行交换{tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;//这里仅仅只是交换一对字节,因为char类型是1个字节//交换完这一对字节,那我们就换下一对字节进行交换,因为buf1和buf2都是指针,那么我们利用指针的加减来实现字节间的加加buf1++;buf2++;//这个循环总共进行width次,每次一对字节交换}
}//size_t是无符号整型
void bubble_sort(void *base,size_t sz,size_t width,int(*cmp)(const void*p1, const void* p2))//将函数的形参改成void*,因为我们不知道传过来的是什么类型的数据
//而恰好void*可以接收任意类型的地址,那么bubble_sort这个函数就能处理任意类型的数据了//这里的base指向的是数组的首元素的地址,sz是数组元素个数
//仅仅知道这两个消息是仅仅不够的,因为我们不知道每个元素的字节大小是多少,因为不同类型的元素字节大小不同//解释一下这个函数,第一个接收的是数组首元素的地址,第二个是数组元素个数,第三个是元素之间的宽度,就是字节大小
//第四个就是比较函数
{//趟数for (int i = 0; i < sz-1; i++){//一趟内部的两两比较for (int j = 0; j < sz - 1 - i; j++){//唯一要改变的就是下面的比较的代码了//1.比较两个元素if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)//如果比较函数的返回值大于0,就进行交换//如果传过去的元素满足条件大于0满足交换的条件,那么就进入条件语句进行交换//那么我们需要将arr[j]的地址和arr[j+1]的地址传到比较函数进行大小比较//元素之间的字符大小根据j的变化来表示,j*width//将base强制转换成char*指针,因为对于char*来说,加几就是跳过几个字节//(char)base+width{//2.交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);//将起始地址传过去,但是并不知道交换多宽的数据,我们就一定得将宽度传过去//将两个交换的元素传过去,还有宽度也传过去
//交换的是(char*)base + j * width和  (char*)base + (j + 1) * width这两个地址指向的元素}}}
}
print(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void test1()
{int arr[] = { 3,1,7,9,4,2,6,8,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);//cmp_int就是最前面的比较函数print(arr, sz);
}void test2()
{struct stu arr[] = { {"zhangsan", 20},{"lisi",35},{"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);}
void test3()
{struct stu arr[] = { {"zhangsan", 20},{"lisi",35},{"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}int main()
{test1();//对于整型数组//test2();//对于结构体--姓名//test3();//对于结构体--年龄return 0;
}//p1和p2指向的是我要比较的两个元素
//因为排序我们得知道他们的大小才能进行,那么这个bubble_sort的第四个形参的那个比较函数的返回值就体现了他们的大小
//
// 
// 
// 
// 对于不同的类型的数据间的比较,我们要将内循环里面的比较条件语句进行改变
//
// 
// 整理一下:
// 拿这个整数数组排列来说
// 
// 首先我们先创建了一个test函数,test函数里面有数组的创建和数组长度的计算,还有一个冒泡函数
// 
// 对于冒泡函数,
// 我们传过去了一个首元素的地址--就是数组名
// 还传过去数组的长度
// 还有数组元素之间的宽度,因为我们不知道不同元素间的宽度
// 最后还传了一个比较数组函数的函数名字
// 
// 
// 
// 在经典的冒泡函数中,我们利用两层循环对数组进行排序
// 
// 而面对不同的元素的时候,这个比较的条件一定是要进行更换的,但是两层循环可以不用动
// 
// 
// 在我们创建冒泡函数接受传来的实参的时候,有这么几个元素
// 
// 我们用void*base来接受传来的数组名,因为我们并不知道传来的是什么类型的数据,恰好void*类型就可以接待任何类型的数据了
// 
// 在后面,我们创建了size_t sz来接受数组长度,size_t就是无符号整型的意思
// 
// 在后面我们又创建了一个size_t width,用来接收传来的数组中元素之间的字节宽度
// 
// 最后,因为下面传来的实参是比较数组中两个相邻元素的函数,那么我们就用一个函数指针进行接收,一定是比较函数哦
// 在这个函数指针创建的时候,可是有说法哦
// int(*cmp)(const void *p1,const void *p2)
//返回类型是整数的函数指针,返回类型有三种,大于0,等于0,小于0的整数
// 利用返回的值进行判断,判断是否交换这两个相邻的元素的位置
// 
// 而里面的const void *p1就是来接受任何类型的地址
// 
// 说完冒泡排序的外面,再说里面吧
// 
// 出了基本的两层循环,改变的就是里面的条件语句
// if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
// 利用传来的比较函数,我们比较了数组中相邻的两个元素的大小,如果返回值>0,我们就让这两个相邻的元素进行交换
// 将base的指针类型强制转换成char*类型的指针
// (char*)base + j * width这个就是这个比较函数的第一个元素,也是起始点
// (char*)base + (j + 1) * width这个是第二个元素,结束点
// 
// 将两个元素传到比较函数里面,返回的值就是return *(int*)p1-*(int*)p2
// 
// 可能你们又忘了为什么这么写:
// p1的类型在上面是void*类型,我们就需要将其强制转换到整型元素,再对其进行解引用操作,返回的值就是这两个元素之间的差值,反应两个元素的大小
// 
// 
// 为什么后面还有j*width呢?
// 随着j的变化,从0到sz-1-i,因为char类型的数据是1个字节的,如果我们有了width了,我们就知道我们该从哪里比较,到哪里停止了
// 
// 
// 
// 那么就进入这个if条件语句里面的Swap交换函数了
// 
// 这个交换函数可有意思
// 传过来的元素地址:(char*)base + j * width, (char*)base + (j + 1) * width,width
// 
// 因为传过来的是地址,所以我们就用指针进行接收,我们还接受了元素的宽度
// 在这个函数里面,我们创建了一个临时变量tmp
// 还创建了一个循环 ,i从0开始,到width结束,就是循环width次,有多少个字节就交换几次,下面的就是很常见的交换的步骤了
// 但是是指针之间的交换,这些指针都是1个字节,因为传过来的是char*类型的指针
// 
// 再后面,就进行指针++,换另一个字节,直到两个元素之间的字节都交换完成,那么这两个元素就交换完成了
// 交换四对字节
// 
//这些代码没有具体类型的要求,你只要传一个数据,我们都能接受
// 因为我们使用void*类型的指针进行存储的

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

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

相关文章

AI高考大战,揭秘五大热门模型谁能问鼎数学之巅?

在高考前&#xff0c;我就有想法了&#xff0c;这一次让AI来做做高考题。就用国内的大模型&#xff0c;看哪家的大模型解题最厉害。 第一天考完&#xff0c;就拿到了2024高考数学2卷的电子版&#xff0c;这也是重庆市采用的高考试卷 这次选了5个AI工具&#xff0c;分别是天工&a…

帕友饮食改善的小建议!

一、增加膳食纤维的摄入 帕金森病患者应增加膳食纤维的摄入量&#xff0c;以帮助调节肠道功能&#xff0c;预防便秘。膳食纤维丰富的食物包括蔬菜、水果、全谷类食物等。患者应确保每天摄入足够的膳食纤维&#xff0c;以保持肠道通畅&#xff0c;缓解帕金森病可能带来的消化不…

[AIGC] Springboot 自动配置的作用及理由

在详细解释SpringBoot的自动配置之前&#xff0c;先介绍以下背景知识。在创建现代复杂的应用程序时&#xff0c;一个困难的部分是正确地设置您的开发环境。这个问题尤其在Java世界中尤为突出&#xff0c;因为您必须管理和配置许多独立的标准和技术。 当我们谈论Spring Boot的自…

代码随想录算法训练营第五十二天|188.买卖股票的最佳时机Ⅳ

188.买卖股票的最佳时机IV 代码随想录 . - 力扣&#xff08;LeetCode&#xff09; 这道题目与之前题目不同的是&#xff1a;限制了k笔交易 设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。 确定dp数组以及下标的含义 每多交易一次就会多两个状态&#x…

【Unity】官方文档学习-光照系统

目录 1 前言 2 光照介绍 2.1 直接光与间接光 2.2 实时光照与烘焙光照 2.3 全局光照 3 光源 3.1 Directional Light 3.1.1 Color 3.1.2 Mode 3.1.3 Intensity 3.1.4 Indirect Multiplier 3.1.5 Shadow Type 3.1.6 Baked Shadow Angle 3.1.7 Realtime Shadows 3.1…

数据挖掘--分类

数据挖掘--引论 数据挖掘--认识数据 数据挖掘--数据预处理 数据挖掘--数据仓库与联机分析处理 数据挖掘--挖掘频繁模式、关联和相关性&#xff1a;基本概念和方法 数据挖掘--分类 数据挖掘--聚类分析&#xff1a;基本概念和方法 基本概念 决策树归纳 决策树:决策树是一…

C#面:请解释web.config⽂件中的重要节点

在C#中&#xff0c;web.config文件是一个XML格式的配置文件&#xff0c;用于配置ASP.NET应用程序的各种设置。web.config文件中包含了许多重要的节点&#xff0c;下面是一些常见的重要节点及其作用&#xff1a; <configuration>节点&#xff1a;web.config文件的根节点&…

如何提高网站访问量?

提高网站访问量通常需要一个多方面的策略&#xff0c;涉及SEO、内容营销、社交媒体和其他网络营销手段&#xff0c;而我们仅从seo入手来说说 关键词优化是SEO的核心&#xff0c;它确保网站能够针对潜在用户的搜索查询进行优化。这不仅涉及在网站内容中使用正确的关键词 还需要…

Python量化交易学习——Part6:多因子选股策略实战(2)

本节主要是针对上节讲解的进行回测: 策略: 首先根据上节所选的因子进行选股,各个因子的权重都设置为1,之后对加权后的因子进行排序,选择因子权重值大的5只股票,进行买入,每个月执行一次上述策略,看最终收益率情况如何。 首先先编写函数代码,新建一个py文件,我们这里…

问题:前肢的前方称() #微信#经验分享#微信

问题&#xff1a;前肢的前方称&#xff08;&#xff09; A . 掌侧 B . 跖侧 C . 背侧 D . 胫侧 E . 桡侧 参考答案如图所示

TOGAF数字化转型的关键(文尾附在线TOGAF免费测试)

业务架构驱动数据架构和应用架构的设计&#xff0c;而应用架构又依赖于数据架构和技术架构的支持。技术架构则为整个架构提供了稳定的基础设施。 在数字化转型中&#xff0c;协调和整合这四种架构是至关重要的。通过确保它们之间的一致性和协同工作&#xff0c;可以实现企业业务…

【CSS】clip-path 属性详解

目录 基本语法值几何形状SVG 引用URL 引用 示例结合动画 clip-path 属性用于在 SVG 和 HTML 中创建复杂的裁剪区域&#xff08;即剪切路径&#xff09;&#xff0c;从而只显示元素的一部分。 基本语法 selector {clip-path: value; }值 clip-path 属性接受以下类型的值&#…

【工具】Redis的安装使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Redis简介二、Redis的安装使用三、本文总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 随着开发语言及人工智能工具的普及&am…

Unity学习要点

前言 学习Unity作为游戏开发的强大工具&#xff0c;对于初学者来说&#xff0c;掌握一些基础而实用的技巧是非常重要的。这不仅能帮助你更快地上手&#xff0c;还能在项目开发过程中提高效率。以下是一些Unity初学者的使用技巧&#xff0c;希望能为你的学习之旅提供帮助。 ##…

极简主义在UI设计中的应用及解析

极简主义&#xff0c;即“少就是多”。在设计中&#xff0c;极简主义是许多艺术概念之一&#xff0c;它描述了一种内容形式&#xff0c;可以在许多方面使用。现在移动UI界面和网页设计中的极简主义设计越来越多。即时设计认为&#xff0c;极简主义UI界面不仅美观&#xff0c;而…

HTTP/HTTPS Testing Magic Tool GO-VCR

目录 What is go-vcr ?Why Use go-vcr?How Does go-vcr Work?How Integrate into your TestingConclusion When developing applications that rely on external APIs, testing can become a challenge. You want your tests to be reliable, fast, and not dependent on th…

[经验] 昆山教育网(昆山教育网中小学报名) #媒体#职场发展#微信

昆山教育网&#xff08;昆山教育网中小学报名&#xff09; 昆山教育局网站 网站&#xff1a;昆山市教育局 昆山市教育局全面贯彻执行党和国家的教育方针、政策&#xff0c;落实有关教育工作的法律、法规&#xff1b;负责制定本市教育工作的实施意见和措施&#xff0c;并监督…

TriForce: 突破长序列生成瓶颈的分层投机解码技术

在人工智能领域&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的长序列生成能力一直是研究的热点。然而&#xff0c;随着模型规模的增长&#xff0c;推理过程中的内存和计算瓶颈成为了限制其应用的主要障碍。为了解决这一问题&#xff0c;Carnegie Mellon University和…

1867java银证转账系统系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java银证转账系统系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&a…

骑砍2霸主MOD开发(11)-瓦兰迪亚火骑兵

一.火焰灼烧Timer public class FlameCavalryTimer_1 : PLCommonBasicMissionTimer{private Mission _mission;public FlameCavalryTimer_1(Mission mission, float triggerInterval, bool isTriggerOnce) : base(triggerInterval, isTriggerOnce){_mission mission;}public o…