排序仔细回顾

目录

 1.冒泡排序

2.插入排序

3.选择排序

 4.希尔排序

5.快排

注:

6.快排(非递归)

7.归并排序

8.归并排序(非递归)

9.计数排序

10.堆排序


 1.冒泡排序

冒泡排序作为第一个学习的排序,实际效率其实并不是很高,更多的是教学意义

基础逻辑:将第一个元素依次与后面一个值进行比较,每趟可以确定最后一个值 

时间复杂度:最坏O(N^2) 最好O(N)  空间复杂度:O(1) 稳定

using namespace std;

void bubbleSort(int* a,int n)
{
    //这里设置一个标记
    for(int i = 0;i < n;++i)
    {
        int flag = 0;
        for(int j = 0;j < n-1-i;++j)
        {   
            if(a[j] > a[j+1])
            {
                std::swap(a[j], a[j+1]);
                flag = 1;
            }    
        }
        if(flag == 0)
            return;//flag等于0的时候代表没有进行交换,就代表数据已经有序
    }   
}

2.插入排序

 效率不错的一个排序,实际运用也比较勤

 基础逻辑:每一趟将前面的值视为有序,然后将所选值拿出来与前面的值依次比较,进行插入

时间复杂度:最坏O(N^2) 最好O(N)  空间复杂度:O(1)  稳定

void insertSort(int* a, int n)
{   
    for(int i = 0;i < n - 1;++i)
    {
        int end = i;
        int tmp = a[end + 1];
        while(end >= 0)
        {
            if(a[end]>a[end + 1];
            {    
                a[end + 1] = a[end];
                --end;
            }
            else
            {
                break;
            }    
        }a[end+1] = tmp;
}

3.选择排序

很粗糙的一个排序,不常用

基础逻辑:选第一个值作为基础值,然后遍历选出最大的或者最小的值和他进行交换,每趟排序至少可以确定一个值的位置 

时间复杂度:最坏O(N^2) 最好O(N^2)  空间复杂度:O(1)  不稳定

void selectSort(int* a,int n)
{
	int begin = 0,end = n-1;
	while(begin<end)
	{
		int maxi = begin,mini = begin;
		for(int i = begin + 1;i< end;++i)
		{	
			if(a[i] > a[maxi])
				maxi = i;
			if(a[i] < a[mini])
				mini = i;
		}
		std::swap(a[mini],a[begin]);
		//如果最大的数在第一个,那么上一句就会将他换走,此时要进行调整
		if(begin == maxi]
			maxi = mini;
		std::swap(a[maxi],a[end]);
		--end;
		++begin;
	}	
}

 4.希尔排序

不那么容易理解的排序,算快排的一种

基础逻辑:将数据分成几组,假设分成3组,然后将同颜色相连的数据进行排序,依次类推

时间复杂度:平均O(N^1.3)  空间复杂度:O(1)  不稳定

void shellSort(int* a, int n)
{
	int gap = n;
	while(gap>1)
	{
		gap = gap/3+1;
		for(int i = 0;i < n-gap -1;i++)
		{
			int end = 1;
			int tmp = end + gap;
			while(end >= 0)
			{
				if(a[end] > a[end + gap]
				{
					a[end+ gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

注:这里的时间复杂度算法比较困难

假设第一次每一次将数据三分,第一次就是n/3组数据,那么第一趟时间复杂度就为(1+2)*n/3

第二次就是n/9,时间复杂度为(1+2+3+4+5+...+8)*n/9 
依次类推,当到最后一组数据每组只有一个数时,就是标准的插入排序,时间复杂度为O(N^2)

这是最坏情况,所以既定shell排序时间复杂度为O(N^1.3)

5.快排

常规需要掌握的排序

基础逻辑:右边先走,遇到比key值小的停下,然后左边走,遇到比key大的停下,交换。直到他们相遇,交换key和相遇点,此时key左边数据小,右边数据大(默认升序)

时间复杂度:最坏O(N^2) 最好O(N*logN)  空间复杂度:O(logN~N)  不稳定

void quickSort(int* a,int left,int right)
{
	//判断返回条件
	if(left>=right)
		return;
	int begin = left,end = right;
	int key = begin;
	while(begin<end)
	{
		while(begin < end && a[end]>=a[key])
		{
			--end;
		}
		while(begin<end && a[begin] <= a[key])
		{
			++begin;
		}
		std::swap(a[begin],a[end]);
	}
	std::swap(a[key],a[begin]);
	key = begin;
	
	//递归
	quickSort(a,left,key -1);
	quickSort(a,key+1,right);
}
	

注:

你可以做一些提升效率的小修改

key三数取中

int Getmidi(int* a,int left,int right)
{
	int midi = (left+right)>>1;
	if(a[midi]>a[left])
	{
		if(a[left]>a[right]) return left;
		else if(a[midi]<a[right]) return midi;
		else return right;
	}
	else 
	{
		if(a[left]<a[right]) return left;
		else if(a[midi]>a[right]) return midi;
		else return right;
		
}

小区间优化

if(right - left + 1 <= 10)
{
    insertSort(a+left,right-left + 1);
}

6.快排(非递归)

基本逻辑:运用栈进行存储,先右后左,一趟跑完入栈新的数据,每次取完删除

void quickSortnonR(int* a,int left,int right)
{
	std::stack<int> st;
	st.push(right);
	st.push(left);
	

	while(!st.empty())
	{
		int begin = st.top();
		st.pop();
		int end = st.top();
		st.pop();
		
		key = begin;
		while(begin<end)
		{
			while(begin<end && a[end] >= a[key])
			{
				--end;
			}
			while(begin<end && a[begin] <= a[key])
			{
				++begin;
			}
			std::swap(a[begin],a[end]);
		}
		std::swap(a[key],a[begin]);
		key = begin;
		//判断是否需要入栈
		if(key+1<right)
		{
			st.push(right);
			st.push(key + 1);
		}
		if(left<key-1)
		{
			st.push(key-1);
			st.push(left);
		}
	}

7.归并排序

基础逻辑: 不断二分,将分出来的数据排列成有序,最后再将他们返回继续比较

时间复杂度:最坏O(N*logN) 最好O(N*logN)  空间复杂度:O(logN)  稳定 

void _mereSort(int*a,int* tmp,int left, int right)
{
	//判断条件
	if(left>=right)
		return;
	
	//找中点
	int midi = (right+ left)>>1;
	//递归!:范围必须在[left,midi],[midi+1,right]而不能是midi-1和midi
	//这里我们拿1,2举例,中点为1,区间就为[0,0][1,1],但如果是midi-1形式就为[0,-1][0,1]左边就会越界
	_mergeSort(a,tmp,left,midi);
	_mergeSort(a,tmp,midi+1,right);
	
	int begin1 = left,end1 = midi;
	int begin2 = midi+1,end2 = right;
	int i = begin;
	while(begin1<=end1 && begin2<=end2)
	{
		if(a[begin1]<a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while(begin1<=end1)
	{
		tmp[i++] = a[begin1++];
	}
	while(begin2<=end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a+left,tmp+left,sizeof(int)*(right-left+1));
}

void mergeSort(int *a,int n)
{
	//开n个空间给tmp临时变量,之后拷贝回给原数组
	int* tmp = (int*)malloc(sizeof(int)*n);//new int[n]
	if(tmp = NULL)
	{
		perror("malloc failed");
		exit(1);
	}
	
	_mergeSort(a,tmp,0,n-1);
	
	free(tmp);delete[] tmp;
	tmp = NULL;
}

8.归并排序(非递归)

这里用循环的方法进行

void mergeSortnonR(int* a, int* tmp,int n)
{
	int* tmp = new int[n];
	
	int gap = 1;//每组单边数据数量
	while(gap<n)
	{
		for(int i = 0;i<n;i+=gap)
		{
			int begin1 = i,end1 = i+gap-1;
			int begin2 = i+gap,end2 = i+2*gap -1;
			int j = 0;
			
			if(end1 >= n)
				break;
			
			if(end2>=n)
				end2 = n-1;
			
			while(begin1<=end1 && begin2<=end2)
			{
				if(a[begin1] < a[begin2]
					tmp[j++] = a[begin1++];
				else
					tmp[j++] = a[begin2++];
			}
			while(begin1<=end1)
				tmp[j++] = a[begin1];
			while(begin2<= end2)
				tmp[j++] = a[begin2];
	
			memcpy(a + i,tmp + i,sizeof(int)*(end2-i+1));
		
		}gap*=2;
	}
	delete[] tmp;
	tmp = NULL;
}

注:可能会存在越界行为

所以这几行很重要 

//判断左边有没有越界
if(end1 >= n)
	break;

//判断最后一个数有没有越界			
if(end2>=n)
	end2 = n-1;
			

9.计数排序

面对在一定范围内的连续的数字排序很好用,不适用完全不规律的数据组

 时间复杂度:O(N)  空间复杂度:O(N)  

void countSort(int* a,int n)
{
	//找出最大值和最小值确定范围
	int maxi = 0,mini = 0;
	for(int i = 0;i<n;++i)
	{
		if(a[maxi] <a[i])
			maxi = i;
		if(a[mini] >a[i])
			mini = i;
	}
	
	int range = maxi - mini + 1;
	vector<int> v(range,0);
	
	for(int i = 0;i<n;++i)
	{
		v[a[i]-min]++;
	}
	
	//覆盖原数组
	int j = 0;	
	for(int i = 0;i<n;++i)
	{
		while(v[i]--)
			a[j++] = i+min;
	}
}

10.堆排序

以二叉树为原理的排序

时间复杂度:最坏O(N*logN) 最好O(N*logN)  空间复杂度:O(1)  不稳定 

void AdjustDown(int* a,int parent,int n)
{
	int child = parent*2+1;
	
	while(child<n)
	{
		if(child+1<n && a[child]<a[child+1])
			child++;
		if(a[child]>a[parent])
		{
			std:;swap(a[child],a[parent]);
			parent = child;
			child = parent *2 +1;
		}
		else
			break;
	}
	
}

void heapSort(int* a,int n)
{
	//建堆
	for(int i = (n-1-1)/2;i>=0;--i)
	{
		AdjustDown(a,i,n)
	}
	
	int end = n-1
	while(end >= 0)
	{
		std::swap(a[0],a[end]);
		AdjustDown(a,0,end);
		--end;
	}
}


 

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值