排序分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。 我们这里的八大排序就是内部排序。
快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
冒泡排序
基本思想:
在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
//冒泡排序
void BubbleSort(int *array,int size)
{
int flag = 1;
for (int i = 0; i < size; i++)
{
flag = 0;
for (int j = i+1; j < size; j++)
{
if (array[i]>array[j])
{
Swap(&array[i],&array[j]);
}
}
if (flag == 1)
{
break;
}
}
}
选择排序
单向选择排序
基本思想:
在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
操作方法:
第一趟,从n 个记录中找出关键码最小的记录与第一个记录交换;
第二趟,从第二个记录开始的n-1 个记录中再选出关键码最小的记录与第二个记录交换;
以此类推.....
第i 趟,则从第i 个记录开始的n-i+1 个记录中选出关键码最小的记录与第i 个记录交换,
直到整个序列按关键码有序。
//选择排序
void SelectSort(int *array,int size)
{
int min;
for (int i = 0; i < size; i++)
{
min = i;
for (int j = i; j < size; j++)
{
if (array[j] < array[min])
{
min = j;
}
}
if (i != min)
{
Swap(&array[min],&array[i]);
}
}
}
双向选择排序
基本思路
与单向选择排序一样,在从头部开始排序的同时,我们让其从末端也进行排序,当前后前后两个下标索引相遇就停止,具体代码如下:
//双向选择排序
void SelectSort(int arr[],int size)
{
int minSpace = 0;
int maxSpace = size - 1;
while (minSpace < maxSpace)
{
int minPos = minSpace;
int maxPos = minSpace;
for (int i = minSpace +1; i <= maxSpace; i++)
{
if (arr[i] > arr[maxPos])
{
maxPos = i;
}
if (arr[i] < arr[minPos])
{
minPos = i;
}
}
Swap(arr + minSpace,arr + minPos);
if (minSpace == maxPos)
{
maxPos = minPos;
}
Swap(arr + maxSpace,arr + maxPos);
minSpace++;
maxSpace--;
}
}
插入排序:
基本思想
将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。
如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
//直接插入排序
void InsertSort(int *array, int size)
{
int temp,i,j;
for (i = 1; i < size; i++)
{
temp = array[i];//取出一个未排序的数
for (j = i-1; j >= 0 ;j--) //在排序序列中查找位置
{
if(temp<array[j])
{
array[j + 1] = array[j]; // 向后移动数据
}
else
{
break;
}
}
array[j+1] = temp; //将数据插入
}
}
//优化后的插入排序--折半插入排序
void BinaryInsertSort(int *array,int size)
{
int i, j, left, right, mid;
int key;
for (i = 1; i<size;i++)
{
key = array[i];
left = 0;
right = i - 1;
while (left <= right)
{
mid = left + (right - left);
if (array[mid]<= key)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
for (j = i; j>left; j--)
{
array[j] = array[j - 1];
}
array[left] = key;
}
}
希尔排序
//希尔排序
void ShellSort(int *arr,int size)
{
int d, i, j, x;
d = size / 2;
while(d>=1) //循环至增量为1时结束
{
for ( i = d; i < size; i++)
{
x = arr[i]; //获取序列中的下一个数据
j = i - d; // 序列中前一个数据的序号
while (j >= 0&&arr[j]>x) // 下一个数大于前一个数
{
arr[j + d] = arr[j]; //将后一个数向前移动
j = j - d; //修改序号,继续向前比较
}
arr[j + d] = x; //保存数据
}
d /= 2; //缩小增量
}
}
堆排序
堆排序:树形选择排序,将带排序记录看成完整的二叉树,第一步:建立初堆,第二步:调整堆
方案一:降序排序,建立小堆
//第二步:调整堆
void HeapAdjust(int arr[], int s, int n)
{
//调整为小根堆,从小到大
int rc = arr[s];
for (int j = 2 * s; j <= n; j *= 2)
{
if (j<n && arr[j]>arr[j + 1])//判断左右子数大小
j++;
if (rc <= arr[j])
break;
arr[s] = arr[j];
s = j;
}
arr[s] = rc;
}
//第一步:建初堆
void CreatHeap(int arr[], int n)
{
//小根堆
for (int i = n / 2; i > 0; i--)
HeapAdjust(arr, i, n);
}
//整合
void HeapSort(int arr[], int n)
{
CreatHeap(arr, n);//第一步,建立初堆
for (int i = n; i > 1; i--)
{
int x = arr[1];//堆顶与最后一个元素互换
arr[1] = arr[i];
arr[i] = x;
HeapAdjust(arr, 1, i - 1);
}
}
方案二:升序排序,建立大堆
void AdjustDown(int arr[], int size, int root)
{
int left = 0;
int right = 0;;
int maxChild = 0;
while (1)
{
left = 2 * root + 1;
right = 2 * root + 2;
//判断左孩子是否越界
if (left >= size)
{
return;
}
//判断左右孩子谁是最大的
maxChild = left; //假设是左孩子
if (right <size && arr[right] > arr[left])
{
maxChild = right;
}
//判断最大的是不是在根处,不是的话进行交换
if (arr[root] >= arr[maxChild])
{ //判断是否满足大堆性质
return;
}
Swap(&arr[root],&arr[maxChild]);
root = maxChild;
}
}
void HeapSort(int arr[],int size)
{
//建立初堆
for (int i = (size - 2) / 2; i >= 0; i--)
{
AdjustDown(arr, size, i);
}
for (int j = 0; j < size - 1; j++)
{
Swap(&arr[0],&arr[size-j-1]);
AdjustDown(arr,size-j-1,0);
}
}
归并排序
//归并排序
快速排序
方法一:左右指针法
//左右指针法,选的基准值放在最右边
int Partion(int arr[],int left,int right)
{
int pivot = arr[right];
int begin = left;
int end = right;
while (begin < end)
{
while (begin < end &&arr[begin] <= pivot)
{
begin++;
}
while (begin < end &&arr[end] >= pivot)
{
end--;
}
if (begin == end)
{
break;
}
Swap(arr + begin,arr + end);
}
Swap(arr + begin, arr + right);
return begin;
}
方法二:挖坑法
//挖坑法
int Partion2(int arr[], int left, int right)
{
int pivot = arr[right];
int begin = left;
int end = right;
while (begin < end)
{
while (begin < end && arr[begin] <= pivot)
{
begin++;
}
if (begin == end)
{
break;
}
arr[end] = arr[begin];
while (begin < end && arr[end] >= pivot)
{
end--;
}
arr[begin] = arr[end];
}
arr[begin] = pivot;
return begin;
}
方法三:前后指针法
//前后指针法
int Partion3(int arr[],int left,int right)
{
int pivot = arr[right];
int part = left;
for (int cur = left; cur <= right; cur++)
{
if (arr[cur] < pivot)
{
Swap(arr + cur, arr + part);
part++;
}
}
Swap(arr + right, arr + part);
return part;
}
快速排序
void _QuickSort(int arr[],int left,int right)
{
if (left >= right)
{
return;
}
int pivot = arr[right]; //选取最右边的一个作为基准值
int part = Partion3(arr,left,right);
_QuickSort(arr,left,part-1);
_QuickSort(arr,part+1,right);
}
void QuickSort(int arr[],int size)
{
_QuickSort(arr, 0, size - 1);
}