归并排序
归并排序的思想就是将一个数组分为二组,如果这两组数组是有序的话,那么可以很快将这两组数组进行排序。
那么怎么样才能让这两个数组内的数据都有序呢?
可以通过递归的方法,将两个数组各自再分为两组,以此类推,当每个组都只有一个数据的时候,可以认为有序。
再合并数组。
总结起来:归并排序就是通过递归对数组进行分解,再通过合并,从而完成归并排序。
#include <cstdio>
void mergeArray(int* array, int first, int mid, int last, int* buff)
{
int i, j, m, n,k;
i = first;
j = mid;
m = mid+1;
n = last;
k = 0;
while (i <=j&&m <=n)
{
if (array[i] <=array[m])
buff[k++] = array[i++];
else
buff[k++] = array[m++];
}
while (i <= j)//如果其中一个数组已经全部移动到buff中,则把另一个数组剩余的元素按序移动到buff。
{
buff[k++] = array[i++];
}
while (m <= n)//如果其中一个数组已经全部移动到buff中,则把另一个数组剩余的元素按序移动到buff。
{
buff[k++] = array[m++];
}
for (int q = 0; q < k; q++)
{
array[first + q] = buff[q];//两组数组归并好后替换掉原有的数组
}
}
void mergeSort(int* array, int first,int last,int* buff)
{
if (first < last)
{
int mid = (first + last) / 2;
mergeSort(array, first, mid, buff);
mergeSort(array, mid + 1, last, buff);
mergeArray(array, first, mid, last, buff);
}
}
bool MergeSort(int* array, int n)
{
int* buff = new int[n];//开辟一个临时空间
if (!buff)
return false;
mergeSort(array, 0, n-1, buff);
delete[] buff;//要记得释放
return true;
}
希尔排序
希尔排序的基本思想是分组插入排序。
基本步骤就是:将整个数组分为若干个子序列,每个子序列的数据相隔某一增量,分别对每个子序列进行直接插入排序。
完成后,再缩小增量,对整个数组进行子序列的重新划分。再对每个子序列进行直接插入排序,以此类推。
直到每个子序列都只有一个单独的数据,最后进行一次直播插入排序。
void shellSort(int* array, int n)
{
for (int gap = n / 2; gap >0; gap /= 2)
{
for (int i = gap; i < n; i++)
{
for (int j = i - gap; j >= 0 && array[j] > array[j + gap]; j -= gap)
{
swap(array[j], array[j + gap]);
}
}
}
}
直接插入排序
void insertSort(int* array,int n)
{
for (int i=1 ; i < n; i++)
{
for (int j = i - 1; j >= 0 && array[j] > array[j+1]; j--)
{
swap(array[j], array[j + 1]);
}
}
}
快速排序
快速排序的主要思想:
【1】选取一个基准,进行分区。将小于基准的数放在基准的左边,将大于基准的数放在基准的右边。对此序列以基准为基准,左边全部是小于基准的数,右边全部是大于基准的数。
【2】运用递归的思想再分别对左右两个半区进行再快速排序。
快速排序的举例说明:
如取array[]={4,7,8,3,6}进行简单说明
【1】取4为基准,i=0, j=4,i用于向右找比4大的数,j用于向左找比4小的数。
【2】首先,先向左找比基准4小的数,6?不是,3?比4小!!此时把基准挖一个坑,并把3填入4的位置,此时基准的坑被填好了,但却出现了一个新的坑,即原来3所在的位置。将值array[0 ]=array[3]后,j–;
【3】接下来,从左向右找一个比基准4大的数,并填入新的坑。7?比4大。好,那么将7这个数值填入新的坑中。array[3]=array[2] ;i++;
【4】当i=j或者是i>j时,停止寻找。
【5】并将基准填入最后出现的坑中。
【6】经历了以上6个步骤后,数组变为3 4 8 7 6 。发现,基准4的左边全是小于4的数,右边全是大于4的数。即成功地进行分区!!
【7】再接下来,运用递归的思想分别再对左右两边进行同样的操作。
//快速排序函数
void quickSort(int* array, int arrayBegin, int arrayEnd)
{
if (arrayBegin < arrayEnd)//确保输入的参数有效,同时也是递归终止的关键
{
int i = arrayBegin;
int j = arrayEnd;
int base = array[arrayBegin];//以目标序列的第一个数为基准
while (i < j)//i=j或者i>j后都不再进行分区
{
while ((i < j) && (array[j] >= base))//从后往前找直到找到比基准小的数
j--;
if (i < j)
array[i++] = array[j];//要注意到是先把array[j]赋给array[i]后,i才自加的。此时把坑array[i]填了后,array[j]变成了坑。
while ((i<j) && (array[i]< base))//while里条件重复一下i<j是有必要的,因为上面的程序会进行 i,j的运算。以防上面的程序运行完后i=j,或者i>j了!!
i++;
if (i < j)
array[j--] = array[i];//要注意到是先把array[i]赋给array[j]后,j才自加的。此时把坑array[j]填了后,array[i]变成了坑。
}
array[i] = base;//到最后留下的坑由基准来填。
quickSort(array, arrayBegin, i - 1);//递归调用对左半区再进行排序
quickSort(array, i + 1, arrayEnd);//递归调用对右半区再进行排序
}
}
冒泡排序
//原理版冒泡排序
void bubbleSort1(int array[],int n)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n - i-1; j++)
{
if (array[j] > array[j+1])
{
swap(array[j], array[j+1]);
}
}
}
}
//优化版冒泡排序
void bubbleSort4(int array[], int n)
{
int numCount = n;
while (numCount>0)
{
int k = numCount;
numCount=0;//如果没有可交换的数,这句的作用就可以使while循环结束。
for (int j = 0; j < k - 1; j++)//比如数组有5个数,则第遍历一次要4次
{
if (array[j] > array[j + 1])
{
swap(array[j], array[j + 1]);
//记录下此时交换数组的位置
//优点:比如说100个数,后90个数都是排序好的
//那么,第一次进行交换的位置j一定在10以内
//记录后赋给一个标志位,从此标志位之后不用再去遍历,而是遍历前10位
//通俗来说,因为后90个已经不再须要排序,我们可以把这个数组当成只有前10位
numCount = j + 1;//为什么+1具体逻辑可能得自己通过特殊取值法来验算
}
}
}
}
//测试主函数
void main()
{
int a[] = { 8,7,10,1,3,5,4,9 };
quickSort(a, 0, 7);
bubbleSort4(a,8);
for (int i = 0; i < 8; i++)
printf("%d ", a[i]);
}