算法的重要性我想就不必多说了,程序的灵魂所在,也是我们解决很多问题的重要工具,可以说是程序猿的必学知识!
本篇主要介绍关于排序方面的算法,本人水平有限,出于学习之中,如有错误之处,望各位大牛批评指正!
排序的种类很多,时间效率和空间效率也不尽相同,各有利弊,不同的排序算法适用于不同的特征数据。
- 插入排序 , 简单直观,将待排序的元素插入到已排序好的子序列中,又可分为直接插入排序、折半插入排序和希尔排序
直接插入代码如下:适用于基本有序的数据,且数据量不大
// 对数组A[] 的A[1]到A[n] 排序
void InsertSort(ElemType A[] , int s){
int i , j ;
for (int i = 2; i < s; i++)
{
if (A[i] < A[i-1]){
A[0] = A[i]; // 哨兵A[0]
for (int j = i-1; A[0] < A[j]; --j)
A[j+1] = A[j]; // 向后挪位置,
A[j+1] = A[0]; // 插入
}
}
}
折半插入代码如下:是上者的改进,但效率并未提升
//折半插入, 对数组A[] 的A[1]到A[n] 排序
void InsertSort(ElemType A[] , int s){
int i , j , low ,high, mid ;
for (int i = 2; i <= s; i++)
{
A[0] = A[i] ;
low = 1 ; high = i -1 ;
while (low <= high)
{
mid = (low + high) / 2;
if (A[mid] > A[0])
high = mid -1; //左半边查找
else
low = mid +1 ;//右半边查找
}
for (int j = i-1; A[0] < A[j]; --j)
A[j+1] = A[j]; // 向后挪位置,
A[j+1] = A[0]; // 插入
}
}
希尔排序代码:将排序表分割成以 特定步长 为单位的子表,然后进行直接插入排序
//希尔排序, 对数组A[] 的A[1]到A[n] 排序
void ShellSort(ElemType A[] , int s){
// 记步长为dk
for (int dk = A[].lenth / 2 ; dk >= 1 ; dk = dk/2)
for (int i = dk + 1; i <= s; i++)
{
if (A[i] < A[i - dk] )
{
A[0] = A[i]; // 哨兵A[0]
for (int j = i-dk; j > 0 && (A[0] < A[j]); j-=dk)
A[j+dk] = A[j]; // 向后挪位置,
A[j+dk] = A[0]; // 插入
}
}
}
2.交换排序, 基于交换的排序有很多,这里只介绍几个重要的,冒泡和快排。
冒泡排序基本思想是从后往前或者从前往后两两比较相邻元素的值,若为逆序,则交换之,直至排序完成。
代码函数如下:
//冒泡排序
void BubbleSort(ElemType A[] , int n){
for (int i = 0; i < n-1; i++)
{
flag = false; //本趟冒泡如未发生交换,说明已排序好
for (int j = n-1; j > i; j--) //一次冒泡
{
if (A[j-1] > A[j]){
swap(A[j-1] , A[j] ); // 交换
flag = true;
}
}
if (flag == false)
return ;
}
}
代码如下:
//快速排序,递归
void QuickSort(ElemType A[], int low, int high){
if (low < high)
{
int pivot = Partition( A[] , low , high );
QuickSort( A[], low, pivot -1);
QuickSort( A[], pivot +1 , high);
}
}
// 找出枢轴值pivot, 该元素将序列划分为两部分
int Partition(ElemType A[], int low, int high){
// 即一趟快排结果
ElemType pivot = A[low]; // 将第一个元素作为初始枢轴值
while (low < high)
{
while (low < high && A[high] >= pivot) --high;
A[low] = A[high] ;
while (low < high && A[low] >= pivot) ++low;
A[high] = A[low] ;
}
A[low] = pivot;
return low ; //返回枢轴最终位置
}
3. 选择排序,选择排序顾名思义,每次选择出一个最小的元素,挨个排在后面,
简单选择排序,思想是:第i趟排序从A[i ... n] 中选择关键字最小的元素与A[i] 交换
代码如下:
//简单选择排序
void SelectSort (ElemType A[], int n){
for (int i = 0; i < n-1; i++)
{
min = i ; //记录最小元素
for (int j = i+1; j < n; j++) //选择出最小的元素
if (A[j] < A[min]) min = j ;
if (min != i ) //与第i个元素交换
swap(A[i] , A[min]);
}
}
4.归并排序 和 基数排序
归并排序也是一种很重要的排序,而且时间效率跟堆排序一样,都是很快的排序。
下面介绍2-路归并排序,你看到下面的图也许就会明白2-路归并的思想。
分解排序,然后合并之。
代码如下:
//归并排序, 要额外的临时空间 B[] 数组
// 合并函数
void Merge(ElemType A[], int low, int mid , int high){
for (int k = low ; k <= high ; k++)
B[k] = A[k] ;
for (int i = low , j = mid +1 , k = i ; i <= mid && j <= high ; k++)
{
if (B[i] <= B[j])
A[k] = B[i++];
else
A[k] = B[j++];
}
// 将未检测完的一次性加到后面,并且下面的两个
// while 循环只会执行一个
while (i <= mid) A[k++] = B[i++] ;
while (i <= mid) A[k++] = B[j++] ;
}
// 归并排序
void MergeSort (ElemType A[], int low, int high) {
if (low < high)
{
int mid = ( low + high )/2; // 从中间划分成两个子序列
MergeSort (A[], int low, int mid); //对左边子序列进行递归排序
MergeSort (A[], int mid +1 , int high); //对右边子序列进行递归排序
Merge (A[], low, mid , high); // 合并
}
}
基数排序也是一种很实用的排序,但有点特别,它是基于关键的重要性进行排序,有分配和收集两个步骤 ,因为关键字不尽相同,所以笔者在这里就不进行代码分享了。
笔者处于学习阶段,难免会有错误疏漏之处,还请各位大牛批评指正!
