有关排序的算法

发布于:2024-06-16 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

选择法排序

冒泡法排序

qsort排序(快速排序)

qsort排序整型

qsort排序结构体类型


排序是我们日常生活中比较常见的问题,这里我们来说叨几个排序的算法。

比如有一个一维数组 arr[8] ={2,5,3,1,7,6,4,8},我们想要把它排成升序,我们通过下面这几种不同的方式来进行排序!

选择法排序

这一种排序方式,首先第一轮认为第一个元素是最小的,把它的下标用 flag 记下来,不断与后面的元素进行比较,如果后面的元素有比它小的,就把 flag 改成比它小的元素下标,直到把整个数组下标遍历完,如果flag不等于最开始的下标就进行交换,这样就可以得到最小的那个数在第一位,依此类推,第二轮找到第二小的数字放在第二位,第三轮找到第三小的数字放在第三位……

当第七轮的时候已经找到了找到第七小的数字放在第七位,显然最后一位是最大的数字,所以一共进行七次就好了!

代码如下:

//选择法排序
#include<stdio.h>
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	int flag = 0;
	printf("排序前:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	for (i = 0; i < sz - 1; i++)
	{
		flag = i;
		for (j = i + 1; j < sz; j++)
		{
			if (arr[j] < arr[flag])
				flag = j;
			//如果后面的元素比flag为坐标的元素小,就把flag改成较小元素的坐标
		}
		if (flag != i)
		{
			int temp = arr[i];
			arr[i] = arr[flag];
			arr[flag] = temp
		}
	}
	printf("\n排序后:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}


当然,在学习了指针的基础上,我们可以把排序代码分装成函数的形式


#include<stdio.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
void Choose_sort(int* arr, int sz)
{
	int flag = 0;
	for (int i = 0; i < sz - 1; i++)
	{
		flag = i;
		for (int j = i + 1; j < sz; j++)
		{
			if (arr[j] < arr[flag])
				flag = j;
		}
		if (flag != i)
		{
			int temp = arr[i];
			arr[i] = arr[flag];
			arr[flag] = temp;
		}
	}
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	Choose_sort(arr, sz);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}



冒泡法排序

这个与选择法排序有点相似,它的核⼼思想是两两相邻的元素进⾏⽐较,如果后面的元素比前面小,那么就立刻进行交换,第一轮最终会把最大的元素放在最后一位,依次往后面推进,在第七轮的时候,第二小的就在第二位了,所以只需要7趟就好了,每一趟就会找到一个元素放在相应的位置,所以每一趟比较的数组元素也会依次减1.

代码如下:


//冒泡排序
#include<stdio.h>
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	printf("排序前:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	for (i = 0; i < sz - 1; i++)
	{
		//i代表趟数
		for (j = 0 ; j < sz - 1 - i; j++)
		{
			//访问数组元素两两比较
			if ( arr[j+1]<arr[j])
			{
				int temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}		
		}	
	}
	printf("\n排序后:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们也可以把排序代码分装成函数的形式:

#include<stdio.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
void Bubble_sort(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (*(arr+j+1) < *(arr+j))
			{
				int temp = *(arr + j + 1);
				*(arr + j + 1) = *(arr + j);
				*(arr + j) = temp;
			}
			/*if (arr[j + 1] < arr[j])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}*/
		}
	}
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	Bubble_sort(arr, sz);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}



我们来考虑一个问题,如果一个数组元素已经有序了,事实上,我们可以不用再进行排序了,那么应该怎么优化这个排序代码呢?

#include<stdio.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
void Bubble_sort(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//最开始就假设有序
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (*(arr + j + 1) < *(arr + j))
			{
				flag = 0;//进来就说明还没有有序,让flag=0
				int temp = *(arr + j + 1);
				*(arr + j + 1) = *(arr + j);
				*(arr + j) = temp;
			}
		}
		if (flag == 1)//一趟下来flag=1,说明没有机会让flag=0,已经有序
		{
			printf("\n已经有序!\n");
			break;
		}
	}
}
int main()
{
	int arr[8] = { 1,2,3,4,5,6,7,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	Bubble_sort(arr, sz);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}



这里我们就可以使用一个flag来进行标记,flag=1,就说明已经有序,跳出循环,当一个数组已经已经有序或者接近有序的时候就可以减少运算次数

qsort排序(快速排序)

想要使用qsort函数呢?我们就需要先对这个函数进行一定的了解。

打开cplusplus网站,我们可以找到相关信息:

qsort(quick sort)事实上是C语言中的一个库函数,底层使用的是快速排序的思想,

并且对任意类型数据都可以进行排序

我们来看看每一个参数

base:指向需要排序数组的首元素地址(指针)

num:base指向数组中的元素个数

size:bas指向的数组中一个元素的字节大小

compar:函数指针,传递函数的地址

compar应该设计成下面这个样子,同时它的返回值也有要求

int compar (const void* p1, const void* p2);

当p1指向的元素小于p2指向的元素时,返回一个小于0的数字

当p1指向的元素等于p2指向的元素时,返回0

当p1指向的元素大于p2指向的元素时,返回一个大于0的数字

qsort排序整型

//测试qsort排序整型

#include<stdio.h>
#include<stdlib.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
int cmp_int(const void* p1, const void* p2)
{
	if (*(int*)p1 > *(int*)p2)
	{
		return 1;
	}
	//知道比较整型,强制类型转换为整型,然后解引用
	else if (*(int*)p1 < *(int*)p2)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}

我们可以看见qsort进行了很好的排序,当然这里因为它的规则是

当p1指向的元素小于p2指向的元素时,返回一个小于0的数字

当p1指向的元素等于p2指向的元素时,返回0

当p1指向的元素大于p2指向的元素时,返回一个大于0的数字

所以我们可以把return语句直接写成:

return *((int*)p1) - *((int*)p2);

#include<stdio.h>
#include<stdlib.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
int cmp_int(const void* p1, const void* p2)
{
	//return *((int*)p1) - *((int*)p2);//默认升序
	//知道比较整型,强制类型转换为整型,然后解引用
	return *((int*)p2) - *((int*)p1); // 降序
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}


使用qsort默认是升序,如果想要降序,交换p1,p2的位置就可以了,比如上面的代码就可以实现降序。

qsort排序结构体类型

//qsort排序结构体类型
#include<stdio.h>
#include<stdlib.h>//qsort头文件
#include<string.h>//strcmp头文件
struct Student
{
	char name[20];
	int age;
};
void Print_arr(struct Student* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%s %d\n", arr[i].name, arr[i].age);
}
int cmp_student_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Student*)p1)->name, ((struct Student*)p2)->name);
	//strcmp比较字符串,比较第一个不同字符的ASCII值
}
int main()
{
	struct Student arr[3] = { {"lihua",18},{"balla",56},{"guna",23} };
	//结构体数组
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_student_by_name);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}

这里依然是比较的时候强制类型转换为结构体类型,使用了结构体访问操作符【->】特殊的是比较字符串需要使用strcmp函数,不清楚的可以看看【数组的使用】那一篇博客对strcmp进行详细讲解。

我们也可以通过年龄来比较,代码如下:

#include<stdio.h>
#include<stdlib.h>//qsort头文件
//#include<string.h>//strcmp头文件
struct Student
{
	char name[20];
	int age;
};
void Print_arr(struct Student* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%s %d\n", arr[i].name, arr[i].age);
}
int cmp_student_by_age(const void* p1, const void* p2)
{
	return (((struct Student*)p1)->age - ((struct Student*)p2)->age);
}
int main()
{
	struct Student arr[3] = { {"lihua",18},{"balla",56},{"guna",23} };
	//结构体数组
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_student_by_age);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}


当然排序算法永远不止于此,还有更多的内容等待着我们去发现,去应用。

加油吧!未来的顶尖程序员们!!!!