经典排序算法总结(C语言)

1.常见算法分类

十种常见排序算法一般分为以下几种: 
(1)非线性时间比较类排序:交换类排序(快速排序和冒泡排序)、插入类排序(简单插入排序和希尔排序)、选择类排序(简单选择排序和堆排序)、归并排序(二路归并排序和多路归并排序);

(2)线性时间非比较类排序:计数排序、基数排序和桶排序。

总结: 
(1)在比较类排序中,归并排序号称最快,其次是快速排序和堆排序,两者不相伯仲,但是有一点需要注意,数据初始排序状态对堆排序不会产生太大的影响,而快速排序却恰恰相反。

(2)线性时间非比较类排序一般要优于非线性时间比较类排序,但前者对待排序元素的要求较为严格,比如计数排序要求待排序数的最大值不能太大,桶排序要求元素按照hash分桶后桶内元素的数量要均匀。线性时间非比较类排序的典型特点是以空间换时间。

注:本博文的示例代码均已递增排序为目的。

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

//动态演示排序
//交换函数 方便下面排序函数的使用
void Swap(int *a,int *b)
{
	int temp ;
	temp = *a;
	*a = *b;
	*b = temp;
}

/*
	******冒泡排序******
	 1,比较两个数的大小
	 2,交换两个数的位置
	 最好情况:顺序O(N)
	 最坏情况:逆序O(N*N)
	****************
*/

void Bubble_Sort(int *a , int n)
{
	//n 个数进行n-1趟排序
	for(int i =0; i < n-1; i++)
	{
		bool flag = false;
		//每趟排序N-i个数两辆比较,交换次数为N-i-1次
		for(int j =0; j <n-i-1; j++)
		{
			//相邻连个数无序 相等的时候不交换 保证了稳定性
			if(a[j] > a[j+1])
			{
				int temp = a[j];
				a[j] = a[j+1];
				a[j+1] = temp;
				flag = true;//表示有交换
			}
		}
		//相邻的元素如果都有顺序 不用进行循环了
		if(flag == false)
		{
			break;
		}
	}
}

/*
	******选择排序******
	每次找到最大的下标 然后放在最后面
	****************
*/

void Select_sort(int arr[],int n)
{
	//n-1次排序
	for(int i = 1; i < n; i++)
	{
		//是本趟要找的最大元素的下标
		int maxIndex = 0;
		for(int j =1; j <= n -i; j++)
		{
			if(arr[j] > arr[maxIndex])
			{
				maxIndex = j;
			}
		}
		//将找到的最大元素交换到本趟排序数的最后面
		if(maxIndex != n-i)
		{
			int tmp = arr[maxIndex];
			arr[maxIndex] = arr[n-i];
			arr[n-i] = tmp;

		}
	}
}

/*
	******插入排序******
   	循环移动 直到 arr[j] >= num
	放到 j+1
	如果没有移动 不需要改变
	最好情况:顺序O(N)
    最坏情况:逆序O(N*N)
	****************
*/

void Insert_Sort(int arr[], int n)
{
	for(int i = 1; i < n; i++) //把下标为i的这个元素插入到前面 前面数组是有序的
	{
		//记录要插入的值 否则移动过程中数据丢失
		int num = arr[i];
		int j ;
		//for(j = i; j > 0 && num < arr[j-1];j--) {arr[j] = arr[j-1];}
		// arr[j] = num;
		for(j = i-1; j >= 0; j--)
		{
			//循环移动
			if(num < arr[j])
			{
				arr[j+1] = arr[j];
			}
			else//如果 arr[j] >= num 插入到 j+1
			{
				break;
			}
		}
		//如果不相等证明 移动了 否则    没有移动(证明不需要移动)也就不需要改变
		if(j != i-1)
		{
			arr[j+1] = num;
		}
	}
}

void BinaryInsert_sort(int arr[], int len)
{
	for(int i =1; i <len; i++)
	{
		int num = arr[i];
		int left = 0, right = i -1;
		while(left <= right)
		{
			int mid = (left + right) / 2;
			if(num < arr[mid])
			{
				right = mid - 1;
			}
			else if(num > arr[mid])
			{
				left = mid + 1;
			}
			else
			{
				break;
			}

		}
		for(int j = i -1; j >= left; j--)
		{
			arr[j+1] = arr[j];
		}

		arr[left] = num;
	}
}
/*
	******鸡尾酒排序******
	相当于选择排序 
	同时找到最小与最大的元素 
	节省时间
	*****************
*/

void Cocktailsort(int arr[],int n )
{
	for(int i = 1; i <= n/2; i++)
	{
		//每次都从未排序的第一个开始
		int max = i-1;
		int min = i-1;

		for(int j = i; j <= n -i; j++) //int j = i-1 也可以
		{
			if(arr[j] > arr[max])
			{
				max = j;
			}
			if(arr[j] < arr[min])
			{
				min =j;
			}
		}
		if(max != n-i)
		{
			int tmp1 = arr[max];
			arr[max] = arr[n-i];
			arr[n-i] = tmp1;
		}
		//如果要交换位置是最后位置 然而最后位置的值刚才已经改变
		if(min == n -i) //本来存储的值已经到了 arr[max]的位置
		{
			int tmp = arr[i-1];
			arr[i-1] = arr[max];
			arr[max] = tmp;
		}
		else if(min != i -1 )
		{
			int tmp2 = arr[min];
			arr[min] = arr[i-1];
			arr[i-1] = tmp2;
		}
	}
}

/*
	******归并排序******
	归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,
	该算法采用经典的分治(divide-and-conquer) 策略
	(分治法将问题分(divide)成一些小的问题然后递归求解,
	而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,
	即分而治之)。
	****************
*/

int* Merge(int arr[],int len1,int brr[],int len2)
{
	int* p = malloc(sizeof(int)*(len1+len2));
	int i = 0; 
	int j = 0;
	int k = 0;
	while(i < len1 && j < len2)
	{
		if(arr[i] <= brr[j])
		{
			p[k++] = arr[i++]; 
		}
		else
		{
			p[k++] = brr[j++];
		}
	}
	while(i<len1) p[k++] = arr[i++];
	while(j<len2) p[k++] = brr[j++];
	return p;
}

//如果数组 arr[left,mid] 有序 arr[mid+1 ,right] 有序 合并
void Mergerarr(int arr[],int left , int mid, int right)
{
	int len = mid - left+1;
	int *p = malloc(sizeof(int)*len);
	//把[left ,mid-1]区间的数据移动到p指向的内存

	for(int i =0; i <len; i++)
	{
		p[i] = arr[i+left];
	}

	int i =0;
	int k =left;
	int j = mid+1;
	//把p[0,len-1] arr[mid,right] 合并到 arr[left,right]数组里
	while(i < len && j <= right)
	{
		if(p[i] < arr[j])
		{
			arr[k++] = p[i++];
		}
		else
		{
			arr[k++] = arr[j++];
		}
	}
	while(i < len)
	{
		arr[k++] = p[i++];
	}
}

//归并排序
void Merge_sort(int a[], int left, int right)
{
	if(left < right)
	{
		int mid = (left + right ) / 2;
		Merge_sort(a,left,mid);
		Merge_sort(a,mid+1,right);
		Mergerarr(a,left,mid,right);
	}
}

void Quick(int arr[],int left,int right)
{
	int key = arr[left];
	int i = left;
	int j = right;
	while( i < j)
	{
		for(; i < j&& arr[j] >key;j--);
		if(j > i)
		{
			arr[i] = arr[j];
		}
		for(; i <j&& arr[i] < key; i++);
		if(j > i)
		{
			arr[j]= arr[i];
		}
	}
	arr[i] = key;
	if(i -1> left)
	{
		Quick(arr,left,i-1);
	}
	if(i+1 < right)
	{
		Quick(arr,i+1,right);
	}
}

//快速排序是不稳定的
void Quick_sort(int arr[],int len)
{
	Quick(arr,0,len-1);
}

/*
	***********桶排序***********
	按照大小把这些数据分到不同的桶里
	再对这些桶进行分别排序
	考虑他的疏密情况
*/

void show(int *a,int n)
{
	for(int i = 0; i< n; i++)
	{
		printf("%d ",a[i]);
	}
	printf("\n");
}

int main()
{
	int arr[10] = {3,1,5,7,8,10,2,4,6,9};
	int a[5] = {1,3,5,7,9};
	int b[6] = {2,4,8,10,11,14};
	int *p;
	p = Merge(a,5,b,6);
	show(p,11);
	printf("\n");
	//Cocktailsort(arr,10);
	//Maopaosort(arr,10);
	Quick_sort(arr,10);

	//Insertsort(arr,10);
	show(arr,10);
	int x =1,y=2;
	Swap(&x,&y);
	printf("%d %d\n",x,y);
	printf("\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42205987/article/details/81208159