排序算法总结(八种)

  • 排序__比较排序
  • 插入排序

直接插入排序

 

希尔排序

下面实现代码:

void InsertSort(int*a ,size_t n)
{
	for (int i = 0; i< n - 1; ++i)
	{
		int end=i;
		int temp = a[end+1];      //假装:temp就是下一个要插入的元素
		while (end >= 0)
		{
			if (a[end] > temp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
				break;
		}
		a[end + 1] = temp;        //最后把temp放到end+1的位置
	}

}

void ShellSort(int*a ,size_t n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = (gap/3) + 1;
		for (size_t i = 0; i <(n - gap); ++i)    //当第一个组完了时候所有组都完了,++i表示所有组是同时开始的
		{
			int end = i;
			int temp = a[end + gap];             //下一个要预排序的元素
			while (end >= 0)
			{
				if (a[end] > temp)
				{
					a[end + gap] = a[end];
					end -=gap;
				}
				else
					break;
			}
			a[end + gap] = temp;
		}
	}
}

 

  • 选择排序

简单选择排序

堆排序

 

下面整个建堆的过程:

 

下面是实现代码

//选择排序
void SelectSort(int*a, size_t n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int maxIndex = end;
		int minIndex = begin;
		for (int i = begin; i <= end; ++i)
		{
			if (a[i]>a[maxIndex])
			{
				maxIndex = i;
			}
			if (a[i] < a[minIndex])
			{
				minIndex = i;
			}
		}
		swap(a[begin],a[minIndex]);
		if (maxIndex == begin)
			maxIndex = minIndex;
		swap(a[end],a[maxIndex]);

		++begin;
		--end;
	}
}

//向下调整
void _AdjustDown(int* a,int root,size_t n)
{
	int parent = root;
	int child = parent * 2 + 1;

	while (child < n)               //这是一个完全二叉树,没有左孩子一定没有右孩子
	{
		if (child + 1<= n && a[child + 1]>a[child])  //当柚子树存在并且大于左子数时
			++child;
		
		if (a[parent] < a[child])
		{
			swap(a[parent], a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;	
		}
	}
}

//堆排序
void HeapSort(int*a, size_t n)
{
	//建大堆
	for (int i = ((n - 2)/2); i >= 0; --i)
	{
		_AdjustDown(a,i,n);
	}

	//交换
	int end = n-1;
	while (end >0)
	{
		swap(a[0],a[end]);
		_AdjustDown(a,0,end-1);
		--end;
	}
}

 

  • 交换排序

快速排序:

 

下面是快排的递归和非递归:

//快排递归
void QuickSort(int* a, int left, int right)
{
	if (left > right)
		return;
	//if (right - left < 5)
	//{
	//	InsertSort(a,right-left+1);
	//}

	//这里进行单趟排序
	//int div = partSort(a,left,right);
	//int div = partSort1(a, left, right);
	int div = partSort2(a, left, right);

	QuickSort(a, left, div - 1);
	QuickSort(a, div + 1, right);
}

//快排非递归
void QuickSortNoR(int* a, int left, int right)
{
	stack<int> sta;
	//这里存的是下标
	sta.push(right);
	sta.push(left);
	while (!sta.empty())
	{
		int begin = sta.top();
		sta.pop();
		int end = sta.top();
		sta.pop();

		//这里进行单趟排序
		//int div = partSort(a,begin,end);
		//int div = partSort1(a, begin, end);
		int div = partSort2(a, begin, end);

		if (begin < div - 1)
		{
			sta.push(div-1);
			sta.push(begin);
		}
		if (div + 1 < end)
		{
			sta.push(end);
			sta.push(div+1);
		}
	}
}

左右指针法:



 

代码如下:

//左右指针法
int partSort(int*a, int begin, int end)
{
	int mid = GetMidindex(a,begin,end);
	swap(a[mid], a[end]);
	int &key = a[end];

	while (begin < end)
	{
		while (begin < end && a[begin] <= key)
			++begin;
		while (begin < end && a[end] >= key)
			--end;

	//这里begin找到了第一个大于key的值,end找到了小于key的值
		if (begin < end)
			swap(a[begin],a[end]);
	}
	//这里begin==end
	swap(a[begin],key);
	return begin;
}

挖坑法

代码如下:

//挖坑法
int partSort1(int*a, int begin, int end)
{
	int key = a[end]; //end是坑
	while (begin < end)
	{
		while (begin < end && a[begin] <= key)
			++begin;
		//把begin这个位置的放到坑end中,然后坑变成了begin的位置
		a[end] = a[begin];        

		while (begin < end && a[end] >= key)
			--end;
		//把end这个位置放到坑begin中,然后坑变成end
		a[begin] = a[end];
	}
	//到了这里begin==end,所以坑就是这里
	a[begin] = key;
	return begin;
}


前后指针法:

 

代码如下:

//前后指针法
int partSort2(int*a, int begin, int end)
{
	int cur = begin;
	int prev =begin -1;

	while (cur < end)
	{
		//这里cur是找比key也就是这里的a[end]小的,每次++prev和cur
		if (a[cur] < a[end] && (++prev != cur))
			swap(a[cur], a[prev]);

		++cur;
	}
	//cur==end,交换prev+1和end(也就是我的key)
	swap(a[end],a[++prev]);
	return prev;

}

 

 

归并排序

代码如下:

void _MergeSort(int*a, int left, int right, int*tmp)
{
	if (left >= right)
		return;
	int mid = left + ((right - left) >> 1);
	_MergeSort(a,left,mid,tmp);
	_MergeSort(a, mid+1, right, tmp);

	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	int Index = left;                        //tmp的下标

	//下面就是两段区间的合并a[left,mid],a[mid+1,right]
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
			tmp[Index++] = a[begin1++];
		else
			tmp[Index++] = a[begin2++];
	}
	//有一个区间先结束了,就把另一个区间的剩下所有元素拷贝过去
	while (begin1 <= end1)
		tmp[Index++] = a[begin1++];
	while (begin2 <= end2)
		tmp[Index++] = a[begin2++];

	//再把tmp里面的对应位置的元素拷贝回a[]的对应位置
	//这里因为直到知道是int所以就用了memcpy,也可以用类型萃取,来区分深浅拷贝
	memcpy(a+left,tmp+left,sizeof(int)*(right-left+1));

}


//归并排序
void MergeSort(int*a, size_t n)
{
	int *tmp = new int[n];
	_MergeSort(a ,0, n-1,tmp);
	delete[] tmp;
}



// 非递归
void merge_sort(std::vector<int>& vec, int len) {
    std::vector<int> tmp;
    tmp.resize(vec.size());
    for (int seg = 0; seg < len*2;) {
        for (int i = 0; i < len; i += seg + seg+1+1) {
            int index = i;
            int leftStart = i;
            int leftEnd = std::min(leftStart+seg,len-1);
            int rightStart = std::min(leftEnd+1,len -1);
            int rightEnd = std::min(rightStart+seg,len -1);
            while(leftStart <= leftEnd && rightStart <= rightEnd){
                if(vec[leftStart] < vec[rightStart]){
                    tmp[index++] = vec[leftStart++];
                }else{
                    tmp[index++] = vec[rightStart++];
                }
            }

            while(leftStart <= leftEnd){
                tmp[index++] = vec[leftStart++];
            }

            while(rightStart <= rightEnd){
                tmp[index++] = vec[rightStart++];
            }


            for(int j = i;j<=rightEnd;++j){
                vec[j] = tmp[j];
            }
        }

        if(seg == 0){
            seg = 1;
        }else {
            seg = 2*seg+1;
        }

    }

}


  • 排序__非比较排序

计数排序

代码如下:

//计数排序
void Countsort(int* a,size_t n)
{
	int max = a[0];
	int min = a[0];

	for (size_t i = 0; i < n; ++i)
	{
		if (a[i]>max)
			max = a[i];
		if (a[i] < min)
			min = a[i];
	}
	int range = max - min + 1;
	int* newbuf = new int[range];
	memset(newbuf,0,range*sizeof(int));

	for (size_t i = 0; i < n; ++i)
	{
		newbuf[a[i]-min]++;
	}
	int Index = 0;
	for (size_t i = 0; i < range; ++i)
	{
		while (newbuf[i]--)
			a[Index++] = i + min;
	}

	delete []newbuf;
}

 

基数排序:

实现顺序:

 

 

代码如下:

int  Getdigits(int* a, size_t n)
{
	int base = 10;
	int digits = 1;
	for (size_t i = 0; i < n; ++i)
	{
		while (a[i] >= base)
		{
			++digits;
			base *= 10;
		}
	}

	return digits;
}

//基数排序
void BaseSort(int* a, size_t n)
{
	int* buckets = new int[n];
	int digits = Getdigits(a,n);
	int base = 1;

	for (int i = 0; i < digits; ++i)
	{
	     int Counts[10] = {0};
		//counts记录第i位为num的个数
		for (size_t i = 0; i < n; ++i)
		{
			int num = (a[i] / base) % 10;
			Counts[num]++;
		}

		//求个位为i的在Startss的初始位置
		int starts[10] = { 0 };
		starts[0] = 0;                                   //个位为0的起始位置肯定就从0开始
		for (size_t i = 1; i < 10; ++i)
		{
			starts[i] = starts[i - 1] + Counts[i - 1];  //记录这位的在原数组中的起始位置,等于前一个数的起始位置+前一个的个数
		}

		//把数据从a[]放入到buckts[]里,在拷贝会a[]
		for (size_t i = 0; i < n; ++i)
		{
			int num = (a[i] / base) % 10;
			int& pos = starts[num];
			buckets[pos] = a[i];
			++pos;
		}
		base *= 10;
	}

	memcpy(a,buckets,sizeof(int)*n);
	delete[] buckets;
	
}

下面我们对这些排序进行比较分析:


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值