C++基本排序算法详解

#include <stdio.h>  
#include <assert.h>  
#include <stdlib.h>  

#define XT( str ) #str  
#define CNT_ARY( ary ) ( sizeof( ary ) / sizeof( ary[ 0 ] ) )  
typedef int s32;  
typedef unsigned int u32;  

//[注意下面都是以降序排序进行说明]  

//1.冒泡排序特点:  
//每次和相邻元素比较,比较一次大的数往数组内存高地址移动  
//所以叫冒泡排序,移动len - 1次找到最大的数  
//为什么是len - 1次?因为当比较到倒数第二个元素时  
//它的比较的相邻元素就是最后一个元素  
//这样循环len - 1次我们就能找到最大的数,并且把它放在  
//数组的高地址,那么如何将所有数组都排好序呢?  
//eg.for( i = 0; i < len - 1; ++i ) => [2][1][0][3] len - 1次后的结果  
//下一次我们只需要在[2][1][0]他们之间进行比较了len - 1 次  
//此时len - 1中的len 就要变小了 因为 此时 我们比较的元素就没有[3]了  
//循环次数应该就是len - 1 - 1次 => [1][0][2][3] 下次  
//len - 1 - 1 - 1次 =>[0][1][2][3] 排序好所有元素  
//得出下面循环结构:  
//for( i = 0; i < len - 1( 固定长度 ); ++i )    //外层循环控制次数  
//{  
//    for( j = 0; j < len - 1( 固定长度 ) - i( i = 0, 1, 2, 3 ); ++j )    //内层循环负责比较  
//    {  
//        if( p[ j ] > p[ j + 1 ] )  
//    }  
//}  
//冒泡排序算法  
void BubbleSort( s32 *p, u32 len )  
{  
	assert(0 != p);  
	u32 temp = 0;  
	for(u32 i = 0; i < len - 1; ++i )  
	{  
		for( u32 j = 0; j < len - 1 - i; ++j )  
		{  
			if( p[ j ] > p[ j + 1] )  
			{  
				temp = p[ j ];  
				p[ j ] = p[ j + 1 ];  
				p[ j + 1 ] = temp;  
			}  
		}  
	}  
}  

//2.选择排序  
//选择排序就比较好理解了,默认第一个元素为最小元素,然后跟其他元素进行比较  
//发现还有比它小的就记录这个元素的索引,如果跟原来的元素不同那么就交换  
//循环len - 1次找到最小的元素  
//为什么是len - 1次 因为 我们已经默认第一个元素为最小了,无形中自己就不用跟自己比较了  
//那么for( i = 0; i < len - 1; ++i )找到第一个最小元素  
//剩下的元素我们就不用再跟上次找到底元素比较了所以下次找就要排除上个元素:  
//for( i = 0; i < len - 1( 排除默认所以是len - 1次 ); ++i )    //外层循环控制次数  
//{  
//    min_idx = i;  
//    for( j = i + 1( 排除上个元素 ); i < len( 接着找剩下的 ); ++i )  //内层循环负责比较记录索引  
//    {  
//        if( p[ j ] < p[ min_idx ] )  
//    }  
//}  
//选择排序算法  
void SelectSort( s32 *p, u32 len )  
{  
	assert( nullptr != p );  
	u32 min_idx = 0;  
	s32 temp = 0;  
	for( u32 i = 0; i < len - 1; ++i )  
	{  
		min_idx = i;  
		for( u32 j = i + 1; j < len; ++j )  
		{  
			if( p[ j ] < p[ min_idx ] )  
			{  
				min_idx = j;  
			}  
		}  
		if( i == min_idx )  
		{  
			continue;  
		}  
		temp = p[ i ];  
		p[ i ] = p[ min_idx ];  
		p[ min_idx ] = temp;  
	}  
}  

//3.插入排序  
//从第2个元素开始每次与前面有序的元素进行比较  
//意思就是将比较的元素与先前有序的元素进行比较  
//eg.例如排序[3][3][2]  
//[3][3][2]  
//[3][3][3替换] [j] = [j-1] key = 2  
//[3][3替换][3替换] [j] = [j-1] key = 2  
//[2插入][3替换][3替换]  
//[2][3][3]  
//插入排序算法  
void InsertSort( s32 *p, u32 len )  
{  
	assert( nullptr != p );  
	int j = 0;//3,2,1,0,4  
	int temp;  
	for(u32 i = 1; i < len; ++i)        //默认[0] 至 [i - 1] 元素有序   
	{  
		temp = p[ i ];  
		for( j = i; j > 0; --j )        //比较[0]至[i] 元素大小 插入[0]或者维持不变或者插入合适的中间[j]  
		{  
			if( p[ j - 1 ] <= temp )  
			{
				//[j-1]的数据<=temp了
				//那么temp应该放到[j]处
				//[j-1]<=[j]<=[j+1]
				break;
			}  
			p[ j ] = p[ j - 1 ];  
		}  
		p[ j ] = temp;  
	}  
}  

//4.二分排序  
//实际上是插入排序的升级版,将前面已经排序的部分通过二分查找方式找到下一个带插入元素的位置  
//减少元素移动的次数,(插入排序每次都要从0到索引元素的位置进行判断和移动)  
//二分排序算法  
void HalfSort( s32 *p, u32 count)  
{  
	assert( nullptr != p );  
	s32 left = 0;  
	s32 mid = 0;  
	s32 right = 0;  
	s32 temp = 0;  

	//默认第一个元素有序  
	for( u32 i = 1; i < count; ++i )  
	{  
		temp = p[ i ];  
		left = 0;        //每次从0索引作为左区间  
		right = i - 1;    //每次从该搜索的索引的上一个索引左为右区间( [left][x][x][right][i] )  
		//当left > right 时 p[mid]的位置是最适合的此时 mid = right + 1  
		while( left <= right )  
		{  
			mid = ( left + right ) / 2;        //找中间索引  
			if( p[ mid ] > temp )            //中间元素比该索引元素大说明在中间元素的左边  
			{  
				right = mid - 1;  
			}  
			else                            //中间元素比该索引元素大说明在中间元素的右边  
			{  
				left = mid + 1;  
			}  
		}  
		//循环完毕必然left > right 最后一次的p[mid] > temp => temp <= p[mid]
		//mid值即可即: right = mid - 1 => mid = high + 1

		//从右向左移动数据到i处
		//将数据插入right+1处
		//eg.[right+1]<=[other1]<=[other2][i]
		//temp<=[right+1]
		//[temp]<=[right+1]<=[other1]<=[other2]
		for( s32 j = i - 1; j >= right + 1; --j )  
		{  
			p[ j + 1 ] = p[ j ];  
		}  
		p[ right + 1 ] = temp;  
	}  
}  

//打印数组  
void _print_array( s32 *p, u32 len )  
{  
	assert( nullptr != p );  
	for( u32 i = 0; i < len; ++i )  
	{  
		printf( XT( %d\t ), p[ i ] );  
	}  
	printf( XT( \n ) );  
}  

//随机数组  
void _ran_array( s32 *p, u32 len )  
{  
	assert( nullptr != p );  
	for( u32 i = 0; i < len; ++i )  
	{  
		p[ i ] = rand() % 10000;  
	}  
}  


s32 main()  
{  
	s32 array[ 5 ] = {};  

	_ran_array( array, CNT_ARY( array ) );  
	BubbleSort( array, CNT_ARY( array ) );  
	_print_array( array, CNT_ARY( array ) );  

	_ran_array( array, CNT_ARY( array ) );  
	SelectSort( array, CNT_ARY( array ) );  
	_print_array( array, CNT_ARY( array ) );  

	_ran_array( array, CNT_ARY( array ) );  
	InsertSort( array, CNT_ARY( array ) );  
	_print_array( array, CNT_ARY( array ) );  

	_ran_array( array, CNT_ARY( array ) );  
	HalfSort( array, CNT_ARY( array ) );  
	_print_array( array, CNT_ARY( array ) );  

	return 0;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值