目录
一、快速排序 qsort
1.介绍使用:
我们先来看看这个函数的类型及使用方法:
该函数需要的头文件是<stdlib.h>或<search.h>,返回的类型是void;
简单介绍一下他的参数:
第一个:void *base 是一个voidl型的指针,所以我们在这里可以放任何类型的参数(int、char、float等),base 是首元素的地址;
第二个:size_t num 是要排序元素的个个数;
第三个:size_t width 是以字节为单位的数组元素大小;
第四个:int (__cdecl *compare )(const void *elem1, const void *elem2 ) 是比较两个元素大小返回的数值:前一个元素大于后一个元素返回1,等于则返回0,小于则返回-1(在不同编译器下返回值可能不一样,这里是VS编译器),如下:
举个例子吧,我们用整型数组举例:
int com_par(const void* e1, const void* e2)//void*指针可以接受任何类型的数据
{
return *(int*)e1 - *(int*)e2;
}//比较两个整型大小,得出一个返回值
int main()
{
int arr[10] = { 1,3,6,8,7,9,5,2,4,0 };
qsort(arr, 10, sizeof(arr[0]), com_par);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
//如果用浮点型数组,比较大小这一段代码部分只能如下:不然返回的类型为int则会将1.1-1.0得出值为0
int com_par2(const void* e1, const void* e2)//void*指针可以接受任何类型的数据
{
if (*(float*)e1 - *(float*)e2>0)
{
return 1;
}
if (*(float*)e1 - *(float*)e2 < 0)
return -1;
if (*(float*)e1 - *(float*)e2 == 0)
return 0;
}
这里我们得出的是升序排序,如果要得到降序排序可以将比较大小函数那里返回值:return *(int*)e1 - *(int*)e2改为return *(int*)e2-*(int*)e1,就可以实现降序排序,结果如下:
2:模拟实现:
由上已经介绍过该函数的各个参数,所以就先直接上代码:
void my_qsort(void* base, int num, int width, int (*cmp)(const void* e1, const void* e2))
{
int i = 0, j = 0;
for (i = 0; i < num - 1; i++)
{
for (j = 0; j < num - 1 - i; j++)
{
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
不知道你是否察觉到我们的代码形式上是不是像冒泡排序的代码,没错,这就是根据冒泡排序的类型来实现的。
这里的cmp((char*)base + j * width, (char*)base + (j + 1) * width)中的width是指一个元素的字节大小,所以这里的j*width与(j+)*width所表示的就是前一个元素与后一个元素,就这样比较挨着的两个元素,判断返回值r如果>0(前者大于后者,升序排序,如果要降序排序就改为<0)就交换这
两个元素, 这里我们就编写一个Swap函数来进行交换:
void Swap(char* buf1, char* buf2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
然后在主函数调用:
int main()
{
int arr[10] = { 1,3,2,5,4,6,8,7,9,0 };
my_qsort(arr, 10, sizeof(arr[0]), cmp_int);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
}
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
得出结果为:
二、字符串操作函数
头文件为<string>
1.strlen
(1)介绍使用
strlen,返回的是一个数值,使用时的参数为char*类型的数组名(即字符串首的地址);使用如下:
#include<string.h>
#include <stdio.h>
int main()
{
char arr[20] = "abcdefghijk";
int len = strlen(arr);
printf("len=%d\n", len);
return 0;
}
注意:只能实现字符串计数。
(2)模拟实现
先上代码:
int my_strlen(const char* arr)
{
int n = 0;
while (*arr++ != '\0')
{
n++;//只要arr不等于‘\0’,循环一次n就加1
}
return n;
}
只要从首元素开始接着往后走n+1,当*arr为‘\0’时,即arr这个数组中的元素个数统计完得到n,最后返回数值n;运行如下:
2.strcmp
(1)介绍使用
比较两个字符的大小,用ASCALL码比较。
它的两个参数都是char*类型,返回的类型为int型,如下:
举个例子来说明吧:
int main()
{
char arr1[10] = "c";
char arr2[10] = "h";
int et = strcmp(arr1, arr2);
printf(" %d", et);
return 0;
}
返回值为-1,说明c<h。
注: 这里进行比较的是字符对应的ASCALL码。
(2)模拟实现
代码如下:
int str_cmp(char* arr1, char* arr2)//参数为两个char*
{
while (*arr1 == *arr2)
{//如果比较的两个字符相同且当某一个为“\0”时,就返回0
if (*arr1 == '\0')
return 0;
arr1++;
arr2++;
}
//如果比较时两个不同
if (*arr1 > *arr2)
return 1;//arr1字符大于arr2返回1
else if (*arr1 < *arr2)
return -1;//arr1小于arr2返回-1
}
然后在主函数进行调用:
int main()
{
char arr1[10] = "c";
char arr2[10] = "h";
int et = strcmp(arr1, arr2);//库函数
int ret = str_cmp(arr1, arr2);//自己写的
printf(" %d %d", ret,et);//判断我们写的与库函数的结果是否一样
return 0;
}
很明显答案是一样的,所以我们写的没有错。
3.strcpy
(1)介绍使用
拷贝字符串在另外一个数组里面,会覆盖原内容。
两个参数是char*,第一个参数是我们要 拷进的地址,第二个是被拷贝地址,也就是拷贝strSource的内容到strDestination。前提是strDestination的空间要大于等于strSource的空间。
举例:
int main()
{
char arr1[10] = "abcdefg";
char arr2[10] = "asdf";
printf("原arr2=%s\n", arr2);
strcpy(arr2, arr1);
printf("新arr2=%s", arr2);
return 0;
}
(2)模拟实现
void str_cpy(char* arr1, char* arr2)
{
while (*arr1 = *arr2)//这里是直接将arr2赋给arr1,前提是arr2!=‘\0’
{//依次向后移动
arr1++;
arr2++;
}
}
int main()
{
char arr1[10] = "asdfgf";
char arr2[10] = "bfdce";
str_cpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
//当然这里还可以在简便一点,运行结果一样
void str_cpy(char* arr1, char* arr2)
{
while (*arr1++ = *arr2++)
{
;
}
}
结果如下:
4.strcat
(1)介绍使用
将strSource的内容连接到strDestination后面,要求前者有足够的空间容纳后者拷贝进来。
如:
int main()
{
char arr1[20] = "abcd";
char arr2[10] = "efghijk";
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
(2)模拟实现
char* str_cat(char* arr1, char* arr2)
{
while (*arr1)//先让arr1移动到‘\0’处
{
arr1++;
}
while (*arr1++ = *arr2++)//从‘\0’处开始拷贝arr2的内容
{
;
}
}
int main()
{
char arr1[10] = "abc";
char arr2[5] = "def";
str_cat(arr1, arr2);
printf("%s", arr1);
return 0;
}
5.strstr
(1)介绍使用
从string中查找有没有strCharSet中一样的字符串,有就返回string中这段字符串与后面的字符,如果没有就返回一个空指针(NULL);如下:
int main()
{
char arr1[20] = "abcdebcdefgh";
char arr2[10] = "bcdef";
char *ret=strstr(arr1, arr2);
printf("%s", ret);
}
(2)模拟实现
char* str_str(char* arr1, char* arr2)
{
char* s1 = arr1;//接受接受cur中的字符,与arr1进行判断是否相等
char* s2 = arr2;//接受arr2中的每一个字符
char* cur = arr1;//接受arr1中的每一个字符
while (*cur)
{
s1 = cur;
s2 = arr2;
while (*s1 && *s2 && *s1 == *s2)
{//s1与s2都不为‘\0'且s1与s2要相等,就往后面一直查找,当遇到‘\0’就停止
s1++;
s2++;
}
if (*s2 == '\0')//如果是s2为‘\0’,说明在s1中有与s2相等的字符串,就从这里返回cur
return cur;
cur++;//如果s1与s2判断有不相等,然后cur就往后移动一个字符,再进行判断
}
return NULL;//如果判断完,s1中没有s2的字符串就返回一个空指针
}
int main()
{
char arr1[10] = "abcbebcd";
char arr2[5] = "bcd";
char* ret = str_str(arr1, arr2);
printf("%s", ret);
return 0;
}
三、内存操作函数
头文件<string.h>
1.memcpy
(1)介绍使用
将src以count个字节大小拷贝到dest中。如下:
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };
int a1[5] = { 0 };
int i = 0;
memcpy(a1, a, 20);
for (i = 0; i < 5; i++)
{
printf("%d ", a1[i]);
}
}
注意:count是字节单位的大小,而不是个数。
(2)模拟实现
void* my_memcpy(void* dest, const void* str, size_t count)
{
void* ret = dest;//用于返回
while (count--)
{
*(char*)dest = *(char*)str;//赋值
dest = (char*)dest + 1;//因为dest是void型所以先转换为char*类型加1后赋给dest,下同
str = (char*)str + 1;
}
return ret;
}
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };
int a2[5] = { 0 };
my_memcpy(a2, a, 20);
int i = 0;
for (i = 0; i < 5; i++)
printf("%d ", a2[i]);
return 0;
}
但是我们这样写有一个缺点(有的编译器下使用memcpy函数也是这样):
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };
int a2[5] = { 0 };
my_memcpy(a+2, a, 20);
int i = 0;
for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)
printf("%d ", a[i]);
return 0;
}
如果是这样,输出的结果本应该为1 2 1 2 3 4 5 8 9 10,但实际输出结果为:
所以这就略有区别,但是用memmove就不会这样,。
2.memmove
(1)介绍使用
类型与用法与memcpy相似。
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };
int i = 0;
memmove(a + 2, a, 20);
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
return 0;
}
(2)模拟实现
如图,我们要考虑当dest的空间在这个位置时,我们要拷贝src数据(3 4 5 6 7)时,只能从1->5方向这么去拷贝,如果从5->1拷贝就会将前面的3 4 5被覆盖,就会拷贝错误.。
如果当dest的空间为(6 7 8 9 10)时,拷贝src数据就只能从后往前拷贝(10->6),如果从6->10就会覆盖掉6 7。
所以拷贝时当dest在src前面时就从前往后拷贝,当dest在src后面时就从后往前拷贝。
void* my_memmove(void* dest, const void* str, size_t count)
{
void* ret = dest;//作为返回值
if (dest < str)//从前往后拷
{
while (count--)
{
*(char*)dest = *(char*)str;
dest = (char*)dest + 1;
str = (char*)str + 1;
}
}//从后往前拷
else
while (count--)
{
*((char*)dest + count) = *((char*)str + count);
}
return ret;
}
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };
int i = 0;
my_memmove(a + 2, a, 20);
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
return 0;
}
感谢阅读;多多指教