十大排序算法

一、冒泡排序

冒泡排序的原理很简单,就是每次比较相邻的两个元素,如果第i+1个元素小于第i个元素交换两个位置,这样在一次循环过程中最大的元素就会在数组的末尾,然后只要进行n-1次循环,就会将数组排序完成;

void bubbleSort(vector<int>& nums){
	int n=nums.size();
	for (int i=0;i<n-1;i++)
	{
		for(int j=0;j<n-1-i;j++)
		{
			if (nums[i]>nums[i+1])
			{
				int tmp=nums[i];
				nums[i]=nums[i+1];
				nums[i+1]=tmp;
			}
		}
	}
}

二、选择排序

选择排序也是比较简单的一种排序方法,通过不断比较当前元素与该元素之后的所有元素的大小进行排序,例如当前元素为第i个元素,然后从i+1到最后所有的元素中寻找一个最小的元素,与第i个元素交换。

void selectSort(vector<int>& nums){
	int n=nums.size();
	for (int i=0;i<n-1;i++)
	{
		int index=i;
		for (int j=i+1;j<n;j++)
		{
			if (nums[index]>nums[j])
			{
				index=j;
			}
		}
		int tmp=nums[index];
		nums[index]=nums[i];
		nums[i]=tmp;
	}
}

三、插入排序

插入排序的思想就是打扑克牌的排序思想,比如说我们在打扑克牌的时候,每抓取一张扑克牌都会将抓到的扑克牌放到手中牌的合适的位置,插入排序也是这样,前一个元素因为只有一个,所以认为是有序的,从第二个元素开始,与之前的每一个元素进行比较,如果小于之前的某一个元素就与之交换,直到最后一个元素排序完成。

void insertSort(vector<int>& nums){
	int n=nums.size();
	for (int i=1;i<n;i++)
	{
		int j=i;
		while (j>=1&&nums[j]<nums[j-1])
		{
			int tmp=nums[j];
			nums[j]=nums[j-1];
			nums[j-1]=tmp;
			j--;
		}
	}
}

总结

以上三种排序方法分别为冒泡排序,选择排序以及插入排序,三者有共同点和不同点;
相同点:时间复杂度都为O(n2),空间复杂度都为O(1);
不同点

  1. 选择排序是不稳定的,冒泡排序、插入排序是稳定的;
  2. 在这三个排序算法中,选择排序交换的次数是最少的;
  3. 在数组几乎有序的情况下,插入排序的时间复杂度接近线性级别。

四、希尔排序

希尔排序实质上是对插入排序的一种优化,通过比较距离一定间隔的两个元素来进行排序,从而将元素放置在更接近最终的位置;具体的做法是首先定义一个gap,将数组分成gap个子序列,然后对这些子序列进行插入排序;

void shellSort(vector<int>& nums){
	int n=nums.size();
	for (int gap=n/2;gap>=1;gap/=2)
	{
		for (int curIndex=0;curIndex<gap;curIndex++)
		{
			for (int i=curIndex+gap;i<n;i+=gap)
			{
				int j=i;
				while(j>=gap&&nums[j]<nums[j-gap])
				{
					int tmp=nums[j];
					nums[j]=nums[j-gap];
					nums[j-gap]=tmp;
					j-=gap;
				}
			}
		}
	}	
}

五、堆排序

堆排序的思想就是利用堆这种数据结构,通过构建最大堆或者最小堆来实现堆排序。

  1. 首先我们要将整个数组看成一个完全二叉树,例如对于任意的i,left=2i+1,right=2i+2;分别对应于i节点的左子节点、右子节点。
  2. 其次,从右向左开始遍历每一个非叶子结点,例如数组长度为n,则最右边的非叶子节点为n/2-1,然后观察其子结点中的最大值是否大于该值,如果大于该值,就进行交换。此外,对于较左边的非叶子节点/根节点的子节点,可能并非叶子结点,因此,在我们将两个节点进行交换后,还需要考虑交换后的子节点是否还需要调整。
  3. 当遍历到最左边的时候,最大堆就构建好了,然后从堆顶不断取最大元素与数组中的最后一个元素进行交换,在调整前n-2个元素组成的最大堆;
void heapify(vector<int>& nums,int n,int i){
	int largest=i;
	int left=2*i+1;
	int right=left+1;
	if (left<n&&nums[largest]<nums[left])
	{
		largest=left;
	}
	if (right<n&&nums[largest]<nums[right])
	{
		largest=right;
	}
	
	if (largest!=i)
	{
		swap(nums[i],nums[largest]);
		heapify(nums,n,largest);
	}
}

void heapSort(vector<int>& nums){
	int n=nums.size();
	//构建最大堆
	for (int i=n/2-1;i>=0;i--)
	{
		heapify(nums,n,i);
	}
	//取出堆顶元素,与最后一个元素交换
	for (int i=n-1;i>=0;i--)
	{
		swap(nums[i],nums[0]);
		heapify(nums,i,0);
	}
}

六、快速排序

快速排序的原理主要是利用到了分治的思想,具体的步骤如下所示:

  1. 从数组中随机选择一个基准(Pivot),一般可以选择第一个、最后一个或者是中间的元素;
  2. 其次,重新排列元素,使得基准左边的数,都比基准值小,右边的数都比基准值大;
  3. 然后递归的对左右两边的数进行重排列;

快速排序非常重要的一个部分就是分区函数,这一点可以利用双指针来进行;

int partition(vector<int>& nums,int start,int end){
	int left=start+1,right=end;
	//选择第一个元素作为基准;
	int pivot=nums[start];
	while (left<=right){
		while (left<=right&&nums[left]<=pivot)
		left++;
		while (left<=right&&nums[right]>=pivot)
		right--;
		if(left<right)
		{
			swap(nums[left],nums[right]);
		}
	}
	swap(nums[start],nums[right]);
	return right;
}
void quickSort(vector<int>& nums,int start,int end){
	if (start>=end)
	return ;
	int pi=partition(nums,start,end);
	quickSort(nums,start,pi-1);
	quickSort(nums,pi+1,end);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值