常见的几种排序


目录

 

一、冒泡排序:

二 、直接选择排序:

三、直接插入排序:

 四、希尔排序

 五、快速排序

快速排序三种找基准方式及两种优化

 六、堆排

七、归并排序


一、冒泡排序:

  1.     时间复杂性:一般平均是O(n^2),最好的情况是O(n),最坏的情况是O(n^2)。

  2.     空间复杂性:O(1)。

  3.     稳定性:稳定排序。

  4.      冒泡排序的原理:

1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

#include<stdio.h>
void BubbleSort(int *arr,int len)
{
	for(int i=0;i<len-1;i++)
	{
		bool swap = false;
		for(int j=0;j<len-1-i;j++)
		{
			int temp = 0;
			if(arr[j]>arr[j+1])
			{
				temp=arr[j+1];
				arr[j+1]=arr[j];
				arr[j]=temp;
				swap = true;
			}
		}
		if(!swap)
		{
			break ;
		}
	}
}

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

int main()
{
	int arr[]={4,6,1,9,10,11,24,23};
	int len =sizeof(arr)/sizeof(arr[0]);
	BubbleSort(arr,len);
	Show(arr,len);
}

 运行结果如下: 

 

 


 

二 、直接选择排序:

从待排数字开始,后面找到比待排数字小的就发生交换直到排完。

    时间复杂性:O(n^2):最好O(n^2):最坏:O(n^2)。
    空间复杂性:O(1)
    有序    O(n^2)
    无序    O(n^2)

稳定性:不稳定排序

#include<stdio.h>
void SelectSort(int *arr, int len)
{
	for(int i=0;i<len-1;i++)
	{
		for(int j=i+1;j<len;j++)
		{
			int temp=0;
			if(arr[j]<arr[i])
			{
				temp=arr[i];
				arr[i]=arr[j];
				arr[j]=temp;
			}
		}
	}
}
void Show(int *arr,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d  ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={4,6,1,9,10,11,24,23};
	int len =sizeof(arr)/sizeof(arr[0]);
	SelectSort(arr,len);
	Show(arr,len);
	return 0;
}

运行结果如下: 

 

 

 


三、直接插入排序:

直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较, 直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
    时间复杂性:一般平均是O(n^2),最好的情况是O(n),最坏的情况是O(n^2)。
    空间复杂性:O(1)。
    有序    O(n)  越有序越快。
    无序    O(n^2)。
    稳定性:稳定排序。

 

#include<stdio.h>
void InsertSort(int *arr,int len)
	{
		for(int i = 1;i<len;i++)
		{
			int temp=arr[i];
			int j=0;
			for(j=i-1;j>=0;j--)
			{
				if(arr[j]>temp)
				{
					arr[j+1]=arr[j];
				}	
				else
				{
					break;
				}
			}
			arr[j+1]=temp;
		}
	}
void Show(int *arr,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d  ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={4,6,1,9,10,11,24,23};
	int len =sizeof(arr)/sizeof(arr[0]);
	InsertSort(arr,len);
	Show(arr,len);
	return 0;
}

运行结果如下:

 

 


 四、希尔排序

希尔排序简单说就是一种插入排序的优化,是分组插入的方法。

 时间复杂性:一般平均是O(n^1.3),最好的情况是O(n),最坏的情况是O(n^2)。 

空间复杂性:O(1)。

稳定性:不稳定。

代码如下:

#include<stdio.h>
void Shell(int *arr,int len,int gap)
{
	for(int i = gap;i<len;i++)
	{
		int temp =arr[i];
		int j=0;
		for( j = i-gap;j >= 0;j=j-gap)
		{
			if(arr[j]>temp)
			{
				arr[j+gap]=arr[j];
			}
			else
			{
				break;
			}
		}
		arr[j+gap]=temp;
	}
}

void ShellSort(int *arr,int len)
{
	int drr[] ={5,3,1};
	int lend = sizeof(drr)/sizeof(drr[0]);
	for(int i = 0;i < lend;i++)
	{
		Shell(arr,len,drr[i]);
	}
}

void Show(int *arr,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d  ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={4,6,1,9,10,11,24,23,15,56,9,4,8,6,1};
	int len =sizeof(arr)/sizeof(arr[0]);
	ShellSort(arr,len);
	Show(arr,len);
	return 0;
}

 运行结果如下:

 


 五、快速排序

快速排序:是找基准的过程

快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

    时间复杂性:一般平均是O(nlog2n),最好的情况是O(nlog2n),最坏的情况是O(n^2)。
    空间复杂性:O(log2n)。
    稳定性:不稳定排序。

代码如下:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int Partion(int *arr,int low,int high)
{
	int temp = arr[low];
	while(low<high)
	{
		while(low<high&&arr[high]>temp)
		{
			high--;
		}
		arr[low]=arr[high];
		while(low<high&&arr[low]<temp)
		{
			low++;
		}
		arr[high]=arr[low];
	}
	arr[low]=temp;
	return low;
}


void Quick(int *arr,int low,int high)
{
	int key=Partion(arr,low,high);
	if(key-1>low)
	{
		Quick(arr,low,key-1);
	}
	if(key+1<high)
	{
		Quick(arr,key+1,high);
	}
}
void QuickSort(int *arr,int len)//递归
{
	Quick(arr,0,len-1);
}

void QuickSort1(int *arr,int len)//非递归
{
	int top=0;
	int low=0;
	int high=len-1;
	int Timesize= (int)log((double)len)/log((double)2);
	int *stack =(int *)malloc(sizeof(int)*Timesize*2);
	int par =Partion(arr,low,high);
	if(par+1<high)
	{
		stack[top++]=par+1;
		stack[top++]=high;
	}
	if(par-1>low)
	{
		stack[top++]=low;
		stack[top++]=par-1;
	}
	while(top>0)
	{
		high=stack[--top];
		low=stack[--top];
		par=Partion(arr,low,high);
		if(par+1<high)
		{
			stack[top++]=par+1;
			stack[top++]=high;
		}
		if(par-1>low)
		{
			stack[top++]=low;
			stack[top++]=par-1;
		}
	}
	free(stack);
	stack =NULL;
}

void Show(int *arr,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d  ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={1,26,5,8,6,4,12,45,63,2};
	int len = sizeof(arr)/sizeof(arr[0]);
	//QuickSort(arr,len);
	QuickSort1(arr,len);
	Show(arr,len);
	return 0;
}

运行结果:

 

快速排序三种找基准方式及两种优化

快速排序基准数选取三种方式:
1、固定位置基准法:从左到右依次找基准
2、随机选取基准法:以下可以生成随机数;:ps在调用时函数中要加上srand((unsigned int)time(NULL));

#include<time.h>
int main()
{

	int arr[100]={};
	int len = sizeof(arr)/sizeof(arr[0]);
	srand(time(NULL));
	for(int i=0;i<len;i++)
	{
		arr[i]=rand()%100;
	}

	QuickSort(arr,len);
	Show(arr,len);
	return 0;
}

 

3、三数取中法:

void Swap(int *arr,int low,int high)
{
	int temp =arr[low];
	arr[low]=arr[high];
	arr[high]=temp;
}

void SelectPivotMedianOfThree(int *arr,int low,int high)
{
	int mid = (high-low)/2+low;//(high+low)>>1;
	if(arr[high]<arr[low])
	{
		Swap(arr,low,high);
	}
	if(arr[mid]>arr[high])
	{
		Swap(arr,mid,high);
	}
	if(arr[mid]>arr[low])
	{
		Swap(arr,mid,low);
	}
}


快速排序两种优化方式
1、聚集相同基准法

void FocusNumPar(int *arr,int low,int high,int par,int *Left,int *Right )
{
	if(low<high)
	{
		int	parleft=par-1;
		for(int i=par-1;i>=low;i--)
		{
			if(arr[i]==arr[par])
			{
				if(i!=parleft)
				{
					Swap(arr,i,parleft);
					parleft--;
				}
				else
				{
					parleft--;
				}
			}
		}
		*Left=parleft;
		int	parright=par+1;
		for(int i=par+1;i<=high;i++)
		{
			if(arr[i]==arr[par])
			{
				if(i!=parright)
				{
					Swap(arr,i,parright);
					parright++;
				}
				else
				{
					parright++;
				}
			}
		}
		*Right=parright;
	}
}


2、当数据量很少时,采用直接插入排序

void InsertSort(int *arr,int low,int high)
{
	int temp;
	for(int i=low+1;i<=high;i++)
	{
		temp=arr[i];
		int j;
		for(j=i-1;j>=low;j--)
		{
			if(arr[j]>temp)
			{
				arr[j+1]=arr[j];
			}
			else
			{
				break;
			}
		}
		arr[j+1]=temp;
	}
}

 六、堆排

在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:
1、最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
2、创建最大堆(Build Max Heap):将堆中的所有数据重新排序
3、堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算 

  时间复杂性:一般平均是O(nlog2n),最好的情况是O(nlog2n),最坏的情况是O(nlog2n)。
    空间复杂性:O(1)。
    稳定性:不稳定排序。

代码如下:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void Swap(int *arr,int start,int end)
{
	int temp =arr[start];
	for(int i =start*2+1;i<end;i=i*2+1)
	{
		if(arr[i]<arr[i+1]&&i<end)
		{
			i++;
		}
		if(arr[start]<arr[i])
		{
			arr[start]=arr[i];
			start=i;
		}	
	  arr[start]=temp;
	}
}

void Fun(int *arr,int start,int end)
{
	for(int i = start;i>=0;i--)
	{
		Swap(arr,i,end);
	}

}
void Fun2(int *arr,int len)
{
	int end = len-1;
	for(int i=end;i>0;i--)
	{
		Fun(arr,(i-1)/2,i);

		int temp=arr[0];
		arr[0]=arr[i];
		arr[i]=temp;
	}
}

void Show(int *arr,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%5d",arr[i]);
	}
	printf("\n");	
}
int main()
{
	int arr[]={4,9,10,11,24,23,15,56,8,6,1};
	int len =sizeof(arr)/sizeof(arr[0]);
	int end=len-1;
	int start=(end-1)/2;
	//Swap(arr,start, end);
	//Fun(arr,start, end);
	Fun2(arr,len);
	Show(arr,len);
	return 0;
}

运行结果如下:

 

 


七、归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

时间复杂性:一般平均是O(nlog2n),最好的情况是O(nlog2n),最坏的情况是O(nlog2n)。
 空间复杂性:O(n)。
 稳定性:稳定排序。

 代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void Merge(int *arr,int len,int gap)
{
	int *brr = (int *)malloc(sizeof(int) * len);
	assert(brr != NULL);
	int i = 0;//brr的下标
	int start1 = 0;
	int end1 = start1+gap-1;
	int start2 = end1+1;
	int end2 = start2+gap-1 < len-1 ? start2+gap-1 : len-1;

	//当有两个归并段的时候
	while(start2 < len)
	{
		//当两个归并段还没有比较完的时候
		while(start1 <= end1 && start2<=end2)
		{
			if(arr[start1] <= arr[start2])
			{
				brr[i++] = arr[start1++];
			}
			else
			{
				brr[i++] = arr[start2++];
			}
		}
		while(start1 <= end1)
		{
			brr[i++] = arr[start1++];
		}

		while(start2 <= end2)
		{
			brr[i++] = arr[start2++];
		}
		//找两个新的归并段

		start1 = end2+1;
		end1 = start1+gap-1;
		start2 = end1+1;
		end2 = start2+gap-1 < len-1?start2+gap-1:len-1;
	}
	while(start1 < len)
	{
		brr[i++] = arr[start1++];
	}

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

}
void MergeSort(int *arr,int len)
{
	for(int i = 1;i < len;i *= 2)
	{
		Merge(arr,len,i);
	}
}

void Show(int *arr,int len)
{
	for(int i = 0;i < len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={1,26,5,8,6,4,12,45,63,2};
	int len = sizeof(arr)/sizeof(arr[0]);
	MergeSort(arr,len);
	Show(arr,len);
	return 0;
}

运行结果:

 

 


 以上是目前总结的七种排序,在八大排序中,还有一个基数排序,这个目前不做讨论。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值