八大内部排序包括:
l 插入排序:
直接插入排序
希尔排序(又称增量排序)
l 选择排序:
简单选择排序
堆排序
l 交换排序:
冒泡排序
快速排序
l 归并排序
l 基数排序(又称桶排序)
排序算法解析:
1、 直接插入排序与希尔排序
直接排序与希尔排序同属于插入排序,不一样的是,直接排序每次将tmp元素与前面所有的元素进行比较,直到到第一个元素或者当前元素不大于tmp;而希尔排序每次讲tmp元素与前面每隔增量个元素进行比较,直到第一个元素或者当前元素不大于tmp。
直接插入排序代码如下:
void InsertSort( elemtype *arr, int num )
{
//判断传进来的参数是否满足条件
if( arr == NULL )
cerr << EMPTY_ARRAY;
else if( num <= 0 )
cerr << WRONG_ARRAY_CNT;
if( num == 1 )//只有一个元素,直接返回
return;
elemtype tmp;
for( int idx = 1; idx < num; idx++ )
{
tmp = arr[idx];
int i;
//判断并移动元素
for( i = idx-1; i >=0 && tmp < arr[i] ; --i )
arr[i+1] = arr[i];
arr[i+1] = tmp;
}
}
希尔排序代码如下:
void ShellPass( elemtype*, int, int );
void ShellSort( elemtype *arr, int num )
{
int increment = 5 ;
while( increment > 0 )
{
ShellPass( arr, num, increment );
increment /= 2;
}
}
void ShellPass( elemtype *arr, int num, int incre )
{
elemtype tmp;
for( int i = incre; i < num; i++ )
{
int j = i - incre;
tmp = arr[i];
while( j >= 0 && arr[j] > tmp )
{
arr[j + incre] = arr[j];
j -= incre;
}
//if( j != i - incre )//存在比arr[i]小的数,这个实际上加不加都是可以的
arr[j + incre] = tmp;
}
}
2、 选择排序
选择排序每次选择剩下未排序的所有元素中最小的元素。
简单排序每次需要表里剩下的所有元素以获得最小元素,堆排序只需要构建一个最小堆,每次获得堆得根节点,并调整二叉堆即可。
具体简单选择排序代码如下:
int FindMin( elemtype *, int, int);
void ChooseSort( elemtype *arr, int num )
{
//判断传进来的参数是否满足条件
if( arr == NULL )
cerr << EMPTY_ARRAY;
else if( num <= 0 )
cerr << WRONG_ARRAY_CNT;
if( num == 1 )//只有一个元素,直接返回
return;
elemtype tmp;
for( int i = 0; i < num-1; ++i )
{
int min_elem_pos = FindMin( arr, i, num );
tmp = arr[min_elem_pos];
arr[min_elem_pos] = arr[i];
arr[i] = tmp;
}
}
int FindMin( elemtype *arr, int start, int end )
{
if( start > end )
cerr << "Parameter error";
int min_pos = start;
elemtype min = arr[start];
for( int i = start + 1; i < end; ++ i )
{
if( min > arr[i] )
{
min = arr[i];
min_pos = i;
}
}
return min_pos;
}
堆排序算法(暂定)
3、 交换排序
交换排序包括冒泡排序与快速排序。
冒泡排序可以设置一个哨兵判断一个交换过程是否发生交换,如果没有发生交换,说明剩下的数据已经排好序了。
快速排序最重要的是Partition过程,该过程中的i位置表示第i个位置之前的所有元素都小于tmp, j表示遍历到的位置。
冒泡排序代码如下:
void BubbleSort( elemtype *arr, int num )
{
//判断传进来的参数是否满足条件
if( arr == NULL )
cerr << EMPTY_ARRAY;
else if( num <= 0 )
cerr << WRONG_ARRAY_CNT;
if( num == 1 )//只有一个元素,直接返回
return;
elemtype tmp;
bool flag = TRUE;//作为旗帜,判断某一轮是否有交换,如果没有交换,那么排序结束
for( int cnt = 1; cnt < num && flag; ++cnt )//只要排列前面num-1个元素即可
{
flag = FALSE;
for( int j = num-1; j >= cnt; j-- )
{
if( arr[j-1] > arr[j] )//发生交换
{
tmp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = tmp;
flag = TRUE;
}
}
}
}
快速排序代码如下:
int Partition( elemtype *, int, int );
//void Exchange(elemtype *, elemtype * );
//在pre < end的前提下进行排序的
void QuickSort( elemtype *arr, int pre,int end )
{
if( pre < end )
{
int i = Partition( arr, pre, end );
QuickSort( arr, pre, i-1 );
QuickSort( arr, i+1, end );
}
}
//快排最重要的部分, i表示最后一个比tmp小的元素的方位, j表示遍历方位
int Partition( elemtype *arr, int begin, int end)
{
elemtype tmp = arr[end];
int i = begin-1;
for( int j = begin; j < end; ++j )
{
if( arr[j] <= tmp )
{
++i;
elemtype t;
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
elemtype t;
t = arr[i+1];
arr[i+1] = arr[end];
arr[end] = t;
return i+1;
}
4、 归并排序
归并排序是典型的二分法(分治法)排序算法,首先将两个子序列分别排好序,然后合并上述已经排好序的两个子序列,在这里需要开辟一个数组,以便在合并两个排好序的子序列的时候排序,接着把排好序的元素复制到原始数组中。
归并排序代码如下:
elemtype tmparr[MAX_SIZE];//申请一个全局数组,保存交换后的数据
void Merge( elemtype*, int , int, int );//合并数组
void MergeSort( elemtype *arr, int first, int end )
{
if( first == end )//临界条件,数组中是剩下一个元素
return;
int mid = ( first + end ) / 2;
MergeSort( arr, first, mid );
MergeSort( arr, mid + 1, end );
Merge( arr, first, mid, end );
}
void Merge( elemtype *arr, int first, int mid, int end )
{
int i = first;
int j = mid + 1;
int t = first;
while( i <= mid && j <= end )
{
if( arr[i] <= arr[j] )
{
tmparr[t++] = arr[i++];
}
else
{
tmparr[t++] = arr[j++];
}
}
while( i <= mid )
tmparr[t++] = arr[i++];
while( j <= end )
tmparr[t++] = arr[j++];
for( int k = first; k <=end; ++k )
arr[k] = tmparr[k];
}
5、 基数排序(暂定)