10种排序算法 c语言实现和解析

转载请注明出处,如果有笔误请联系我 qq 409746848,后续还会基础出教程,您的关注是我最大的动力。

冒泡 

void MaoPao(int * arr , int size)
{
	if(!arr || size <= 0) return;

	//冒泡算法核心,从头到尾进行排序,每轮找出最小的和第一个进行交换
	//时间复杂度是O(N平方)
	for(int i=0;i<size ; i++)
	{
		//第二轮从第二个开始
		for(int j=i+1;j<size;j++)
		{
			if(arr[i] > arr [j])
			{
				int t = arr[i];
				arr[i] = arr[j];
				arr[j] = t;
			}
		}
	}
}

 

快排

void qsort(int * arr , int l , int h)
{
	//如果低位>=高位表示结束
	if(l>=h) return;

	int i = l,j=h;
	int key = arr[i];//关键位置用的是i就要先将i的值填充

	while(i<j)
	{
		//右边找比key小的放左边
		while(i<j && arr[j]>=key)
		{
			j--;
		}
		arr[i] = arr[j];

		//左边找比key大的放右边
		while(i<j && arr[i]<=key){
			i++;
		}
		arr[j] = arr[i];
	}
	//关键值放入中间位置
	arr[i] = key;
	qsort(arr , l , i - 1);
	qsort(arr, i +1 , h);
}

 

//-------------------------------------------------------------------------------

//选择排序

//-------------------------------------------------------------------------------

//选择排序

void selectSort(int* arr , int size)
{
	//每一次都找出剩下队列中最小的并放置在当前的位置	
	for (int i=0;i<size;i++)
	{
		int minpos = i;
		for (int j=i+1;j<size;j++)
		{
			if (arr[j] < arr[minpos])
			{
				minpos = j;
			}
		}

		int tem = arr[i];
		arr[i] = arr[minpos];
		arr[minpos] = tem;
	}
}

 

//堆排序

void adjustMaxHeap(int a[], int len, int parentNodeIndex) {
	// 若只有一个元素,那么只能是堆顶元素,也没有必要再排序了
	if (len <= 1) {
		return;
	}

	// 记录比父节点大的左孩子或者右孩子的索引
	int targetIndex = -1;

	// 获取左、右孩子的索引
	int leftChildIndex = 2 * parentNodeIndex + 1;
	int rightChildIndex = 2 * parentNodeIndex + 2;

	// 没有左孩子
	if (leftChildIndex >= len) {
		return;
	}

	// 有左孩子,但是没有右孩子
	if (rightChildIndex >= len) {
		targetIndex = leftChildIndex;
	}
	// 有左孩子和右孩子
	else {
		// 取左、右孩子两者中最大的一个
		targetIndex = a[leftChildIndex] > a[rightChildIndex] ? leftChildIndex : rightChildIndex;
	}

	// 只有孩子比父节点的值还要大,才需要交换
	if (a[targetIndex] > a[parentNodeIndex]) {
		int temp = a[targetIndex];

		a[targetIndex] = a[parentNodeIndex];
		a[parentNodeIndex] = temp;


		// 交换完成后,有可能会导致a[targetIndex]结点所形成的子树不满足堆的条件,
		// 若不满足堆的条件,则调整之使之也成为堆
		adjustMaxHeap(a, len, targetIndex);
	}
}

void heapSort(int a[], int len) {
	if (len <= 1) {
		return;
	}

	// 初始堆成无序最大堆
	// 从完全二叉树最后一个非子节点开始
	// 在数组中第一个元素的索引是0
	// 第n个元素的左孩子为2n+1,右孩子为2n+2,
	// 最后一个非子节点位置在(n - 1) / 2
	for (int i = (len - 1) / 2; i >= 0; --i) {
		adjustMaxHeap(a, len, i);
	}

	for (int i = len - 1; i > 0; --i) {
		// 将当前堆顶元素与最后一个元素交换,保证这一趟所查找到的堆顶元素与最后一个元素交换
		// 注意:这里所说的最后不是a[len - 1],而是每一趟的范围中最后一个元素
		// 为什么要加上>0判断?每次不是说堆顶一定是最大值吗?没错,每一趟调整后,堆顶是最大值的
		// 但是,由于len的范围不断地缩小,导致某些特殊的序列出现异常
		// 比如说,5, 3, 8, 6, 4序列,当调整i=1时,已经调整为3,4,5,6,8序列,已经有序了
		// 但是导致了a[i]与a[0]交换,由于变成了4,3,5,6,8反而变成无序了!
		if (a[0] > a[i]) {
			int temp = a[0];
			a[0] = a[i];
			a[i] = temp;
		}

		// 范围变成为:
		// 0...len-1
		// 0...len-1-1
		// 0...1 // 结束
		// 其中,0是堆顶,每次都是找出在指定的范围内比堆顶还大的元素,然后与堆顶元素交换
		adjustMaxHeap(a, i - 1, 0);
	}
}

 

//-------------------------------------------------------------------------------

//插入排序

//-------------------------------------------------------------------------------

//普通插入排序

void InsertSort(int* arr , int size)
{
	//从第一个元素开始,认为第一个元素是已经排序好的队列
	//从后面元素中找到比前一个小的位置
	//从这个位置向前遍历找到比这个位置小的位置插入,否则这个值就往后移动一个位置
	
	for (int i = 1 ; i<size ; i++)
	{
		int prepos = i-1;
		int curval = arr[i];

		while(prepos >=0 && arr[prepos] > curval )
		{
			arr[prepos+1] = arr[prepos];
			prepos-- ;
		}

		arr[prepos+1] = curval;
	}
}

 

//折半插入排序(也叫希尔排序)

void HalfInsertSort(int* arr , int size)
{
	//一半一半的执行插入排除
	for (int i = size/2 ; i>0 ; i = i/2)
	{
		for (int j = i ; j<size ; j++)
		{
			int pos = j;
			int curval = arr[j];
			while(pos-i >= 0 && arr[pos-i] > curval)
			{
				//后移
				arr[pos] = arr[pos-i];
				pos = pos - i;
			}
			arr[pos] = curval;
		}
	}
}

 

//-------------------------------------------------------------------------------

//归并排序

//-------------------------------------------------------------------------------

//二路归并 和 多路归并

//对每一路进行归并排序

void MergeSort(int* arr , int* temp , int startindex,int endindex)
{
	int mid = 0;
	if (startindex < endindex)
	{
		mid = startindex+(endindex - startindex)/2;
		MergeSort(arr,temp,startindex , mid);
		MergeSort(arr,temp,mid+1 , endindex);
		//合并两个数组
		int i=startindex,k=startindex,j=mid+1;

		//两部分对比,取更小的部分继续往后移动
		while(i<mid+1 && j < endindex+1)
		{
			if (arr[i] > arr[j])
			{
				temp[k++] = arr[j++];
			}
			else
			{
				temp[k++] = arr[i++];
			}
		}

		//复制左边剩下的
		while(i < mid+1)
		{
			temp[k++] = arr[i++];
		}
		//复制右边剩下的
		while(j<endindex+1)
		{
			temp[k++] = arr[j++];
		}

		//数组还原
		for (i = startindex ; i<endindex+1 ; i++)
		{
			arr[i] = temp[i];
		}
	}
}

//-------------------------------------------------------------------------------

//非比较排序

//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------

//计数排序,比较的元素差值不要太大

//-------------------------------------------------------------------------------

void CountSort(int* arr , int size)
{
	int max = arr[0],min = arr[0];
	//找出最大和最小
	for (int i=0;i<size;i++)
	{
		if (arr[i] > max) max = arr[i];
		if (arr[i] < min) min = arr[i];
	}

	int newlen = max - min + 1;
	int* newIntArr = new int[newlen];
	memset(newIntArr , 0 , newlen*sizeof(int));

	//开始计数
	for (int i=0;i<size;i++)
	{
		newIntArr[ arr[i] - min ] += 1;
	}

	//开始取出有序填入原数组
	for (int i=0,j=0;i<newlen ; i++)
	{
		while(newIntArr[i]--)
		{
			arr[j++] = i+min;
		}
	}

	delete []  newIntArr;
}

 

//-------------------------------------------------------------------------------

//桶排序 是计数排序的升级版,需要知道:1.几个桶;2.每个桶有几个元素

//-------------------------------------------------------------------------------

typedef struct bucket{
	int k;
	bucket* next;
}bucket;
void bucketSort(int* arr , int size , int bucket_elm_size)
{
	int min = arr[0] , max = arr[0];
	for (int i=0;i<size;i++)
	{
		if(arr[i] > max) max = arr[i];
		if(arr[i] < min) min = arr[i];
	}

	int bucket_count = (max - min) / bucket_elm_size + 1;
	//初始化桶子
	bucket* pbuckets = new bucket[bucket_count];
	for(int i = 0 ;i<bucket_count ; i++)
	{
		pbuckets[i].k = 0;
		pbuckets[i].next = 0;
	}

	//将数据入桶
	for(int i = 0 ;i<size ; i++)
	{
		int index = (arr[i]-min)/bucket_elm_size;
		bucket* pFindBucket = &pbuckets[index];
		//使用插入排序
		bucket* pNewBucket = new bucket;
		pNewBucket->k = arr[i];
		pNewBucket->next = NULL;

		if (pFindBucket->k == 0)
		{
			pFindBucket->k += 1;
			pFindBucket->next = pNewBucket;
		}
		else
		{
			while(pFindBucket->next != NULL && pFindBucket->next->k <= pNewBucket->k )
				pFindBucket = pFindBucket->next;
			
			pNewBucket->next = pFindBucket->next;
			pFindBucket->next = pNewBucket;
			
			pbuckets[index].k += 1;
		}
	}
	
	//输出数据
	for (int i=0,j=0;i<bucket_count;i++)
	{
		for(bucket* pBucket = pbuckets[i].next;pBucket!=NULL;)
		{
			bucket* tmp = pBucket;
			arr[j++] = pBucket->k;
			pBucket = pBucket->next;
			delete tmp;
		}
	}

	delete [] pbuckets;
}

 

 

//基数排序

//需要找到最大数,计算基数,然后存储基数

void RadixSort(int* arr , int size)
{
	unsigned int max = 0;
	for (int i=0;i<size;i++)
	{
		if (abs(arr[i]) > max)
		{
			max = abs(arr[i]);
		}
	}

	int bucketCount = 10;
	int radix = 1;//最大有多少个数量级
	while(max / (int)pow((float)10,radix))
	{
		radix++;
	}

	bucket * pRadixArr = new bucket[10];
	for (int i=0;i<bucketCount;i++)
	{
		pRadixArr[i].k = 0;
		pRadixArr[i].next = NULL;
	}

	int mod = 10;//求余模数
	int dev = 1;//除数
	for (int i=0;i<radix;i++,dev *= 10 , mod *= 10)
	{
		for (int j = 0 ; j< size ; j++)
		{
			bucket* pNewBucket = new bucket;
			pNewBucket->k = arr[j];
			pNewBucket->next = NULL;

			//求出个位或者10位对应的桶序号
			int radixIndex = arr[j] % mod / dev;
			bucket* pFind = &pRadixArr[radixIndex];
			if (pFind->k == 0)
			{
				pFind->k += 1;
				pFind->next = pNewBucket;
			}
			else
			{
				while(pFind->next != NULL && pFind->next->k <= pNewBucket->k) pFind = pFind->next;

				pNewBucket->next = pFind->next;
				pFind->next = pNewBucket;
				pRadixArr[radixIndex].k += 1;
			}
		}

		//从小到大取出桶的数据即可
		int pos = 0;
		for (int j = 0 ; j<bucketCount ; j++)
		{
			if (pRadixArr[j].k)
			{
				bucket* pNode = pRadixArr[j].next;
				while(pNode)
				{
					bucket* pNodeDel = pNode;
					arr[pos++] = pNode->k;
					pNode = pNode->next;
					delete pNodeDel;
				}

				pRadixArr[j].k = 0;
				pRadixArr[j].next = NULL;
			}
		}
	}

	delete[] pRadixArr;
}

 

//十种排序算法


int _tmain(int argc, _TCHAR* argv[])
{
	int aa[]={6,5,8,9,1,10,65,85,95,111,254,3,22,16,28};
	int bb[ARRSIZE(aa)];

	RadixSort(aa,ARRSIZE(aa));
	bucketSort(aa,ARRSIZE(aa),5);
	CountSort(aa , ARRSIZE(aa));
	heapSort(aa , ARRSIZE(aa));
	MergeSort(aa ,bb, 0,ARRSIZE(aa)-1);
	HalfInsertSort(aa , ARRSIZE(aa));
	InsertSort(aa,ARRSIZE(aa));
	selectSort(aa,ARRSIZE(aa));
	MaoPao(aa,ARRSIZE(aa));
	qsort(aa,0,ARRSIZE(aa)-1);


	return 0;
}

 

 

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值