一、排序的概念以及常用排序
1.1 排序中的一些重要概念
- 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
- 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
- 内部排序:数据元素全部放在内存中的排序。
- 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。
1.2 常用的排序算法
接下来我会详细的介绍这几种排序。
二、常见的排序算法
2.1 插入排序
插入排序的大体思路是在有序序列末尾插入数据,然后向前比较调整位置,使得插入后的序列变为有序序列。
代码实现如下:
void InsertSort(int* a, int n)
{
int i;
for (i = 1; i < n; i++)
{
int end = i - 1;
int temp = a[i];
while (end >= 0)
{
if (a[end] > temp)
{
a[end + 1] = a[end];
end--;
}
else
break;
}
a[end+1] = temp;
}
}
2.2 选择排序
选择排序的思路比较简单 ,每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
代码实现如下:
void SelectSort(int* arr, int size)
{
int i = 0;
for (i = 0; i < size-1; i++)
{
int min = i;
int j = 0;
for (j = i+1; j < size; j++)
{
if (arr[j] < arr[min])
{
min = j;
}
}
Swap(&arr[i], &arr[min]);
}
}
2.3 交换排序
(1)冒泡排序
冒泡排序是一种很经典的排序方法 ,其思路也很简单,就是创建一个二重循环每次把最小(最大)的那个元素排到最后去。
实现代码如下:
void BubbleSort(int* a, int n)
{
int i, j;
int flag = 0;
for (i = 0; i < n; i++)
{
flag = 0;
for (j = 0; j < n - i - 1; j++)
{
if (a[j] > a[j + 1])
{
Swap(&a[j], &a[j + 1]);
flag = 1;
}
}
if (flag == 0)
{
break;
}
}
}
(2)快速排序
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
实现代码如下:
int getminIndex(int* arr,int left,int right)
{
int mid = (left + right) / 2;
if (arr[left] > arr[mid])
{
if (arr[left] < arr[right])
{
return left;
}
else
{
if (arr[right] > arr[mid])
{
return right;
}
else
return mid;
}
}
else
{
if (arr[right] > arr[mid])
{
return mid;
}
else
{
if (arr[right] > arr[left])
return right;
else
return left;
}
}
}
int Sort(int* arr,int left,int right)
{
int index = getminIndex(arr, left, right);
Swap(&arr[left], &arr[index]);
int key = arr[left];
int keyi = left;
while (left<right)
{
while (arr[right] >= key && right > left)
{
right--;
}
while (arr[left] <= key && left < right)
{
left++;
}
Swap(&arr[left], &arr[right]);
}
Swap(&arr[keyi], &arr[left]);
return left;
}
//挖坑法
int Sort2(int* arr, int left, int right)
{
int index = getminIndex(arr, left, right);
Swap(&arr[left], &arr[index]);
int key = arr[left];
int hole = left;
while (left < right)
{
while (arr[right] >= key && right > left)
{
right--;
}
arr[hole] = arr[right];
hole = right;
while (arr[left] <= key && left < right)
{
left++;
}
arr[hole] = arr[left];
hole = left;
}
arr[hole] = key;
return hole;
}
// 快速排序前后指针法
int Sort3(int* arr,int left,int right)
{
int index = getminIndex(arr, left, right);
Swap(&arr[left], &arr[index]);
int key = arr[left];
int pre = left;
int cur = left+1;
while (cur <= right)
{
if (arr[cur] < key)
{
pre++;
Swap(&arr[pre], &arr[cur]);
}
cur++;
}
Swap(&arr[left], &arr[pre]);
return pre;
}
void quickSort(int* arr,int begin,int end)
{
if (begin >= end)
return;
int keyi = Sort3(arr, begin, end);
quickSort(arr, begin, keyi - 1);
quickSort(arr, keyi + 1, end);
}
2.4 归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序核心步骤:
实现代码如下:
void MergeSort(int* a, int* tmp, int begin, int end)
{
if (begin >= end)
return;
int mid = (begin + end) / 2;
MergeSort(a, tmp, begin, mid);
MergeSort(a, tmp, mid + 1, end);
int begin1 = begin;
int begin2 = mid+1;
int len = 0;
while (begin1 <= mid && begin2 <= end)
{
if (a[begin1] <= a[begin2])
{
tmp[len++] = a[begin1++];
}
else
{
tmp[len++] = a[begin2++];
}
}
while (begin1 <= mid)
{
tmp[len++] = a[begin1++];
}
while (begin2 <= end)
{
tmp[len++] = a[begin2++];
}
memcpy(a + begin, tmp, sizeof(int)*(end-begin+1));
}
2.5 非比较排序
(1)计数排序
计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 实现方法为先统计相同元素出现次数再根据统计的结果将序列回收到原来的序列中。
代码实现如下:
void CountSort(int* a, int n)
{
int min = 0, max = 0;
for (int i = 0; i < n; i++)
{
if (i == 0)
{
min = a[i];
max = a[i];
}
else
{
if (a[i] > max)
max = a[i];
if (a[i] < min)
min = a[i];
}
}
int* tmp = (int*)malloc(sizeof(int) * (max - min+1));
for (int i = 0; i < max - min + 1; i++)
{
tmp[i] = 0;
}
for (int i = 0; i < n; i++)
{
tmp[a[i] - min]++;
}
int k = 0;
for (int i = 0; i < max-min+1; i++)
{
while (tmp[i])
{
a[k++] = i + min;
tmp[i]--;
}
}
}