基础排序算法: 冒泡排序、选择排序、插入排序、归并排序、希尔排序、快速排序、堆排序
建议看不懂原理说明或图示时请看代码。
冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
算法描述:
/*
1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2. 对第0个到第n-1个数据做同样的工作。这时,最大的数就“浮”到了数组最后的位置上。
3. 针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。
4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较.
*/
// 稳定排序,平均 O(n**2),最好 O(n), 最差 O(n**2),辅助空间 O(1)
void BubbleSort(vector &nums)
{
int n = nums.size();
if (n==0) return;
for (int i=0;i nums[j+1])
{
// swap(nums[j], nums[j+1]);
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
}
选择排序(Select Sort) 是直观的排序,通过确定一个 Key 最大或最小值,再从带排序的的数中找出最大或最小的交换到对应位置。再选择次之。双重循环时间复杂度为 O(n^2)
算法描述:
/*
1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
3. 以此类推,直到所有元素均排序完毕。
*/
// 不稳定排序,平均 O(n**2),最好 O(n**2), 最差 O(n**2),辅助空间 O(1)
void SelectSort(vector &nums)
{
int n = nums.size();
if (n==0) return;
for (int i=0;i nums[j]);
{
idx = j;
}
}
if (idx !=i)
{
int temp = nums[idx];
nums[idx] = nums[i];
nums[i] = temp;
}
}
}
将一个数插入一个已经排好序的数据中。
/*
直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。
1. 从第一个元素开始,该元素可以认为已经被排序
2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
3. 如果被扫描的元素(已排序)大于新元素,将该元素后移一位
4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5. 将新元素插入到该位置后
6. 重复步骤2~5
*/
// 稳定排序,平均 O(n**2),最好 O(n), 最差 O(n**2),辅助空间 O(1)
void InsertSort(vector &nums)
{
int n = nums.size();
if (n==0) return;
// 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
for (int i=1;i=0) && (temp < nums[j])
{
nums[j+1] = nums[j];
j--;
}
nums[j+1] = temp;
}
}
归并排序的主要思想是分治法。主要过程是:
/*
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
1、确定数组的大小,以及输入数组中的元素值;
2、将输入的数组进行分组归并;
3、将整个数组分成左右两个数组,左右两个数组再向下分,直至子数组的元素少于2个时,子数组将停止分割;
4、当左右子数组不能再分割,也是都是一个元素时,比较他们的大小,进行排序合并;
5、再排序合并上一级子数组为两个元素的数组,接着再排序合并上一级子数组为四个元素的数组;直至到排序合并刚开始的两个子数组,最后成为拍好序的数组;
*/
// 稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(nlogn),辅助空间 O(n)
void merge(int array[],int first,int last)
{
int temp[last+1];
int mid=(first+last)/2;
int i=0; //临时数组指针
int l=first;//左序列指针
int r=mid+1;//右序列指针
while(l<=mid&&r<=last)//sort the ele of the left array and the right array
{
if(array[l]
希尔排序,也被称为递减增量排序,是简单插入排序的一种改进版本。
/*
数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。
*/
// 不稳定排序,平均 O(nlogn)-O(n^2),最好 O(nlogn), 最差 O(n**2),辅助空间 O(1)
void ShellSort(int a[],size_t n)
{
int i,j,k,group;
for (group = n/2; group > 0; group /= 2)//增量序列为n/2,n/4....直到1
{
for (i = 0; i < group; ++i)
{
for (j = i+group; j < n; j += group)
{
//对每个分组进行插入排序
if (a[j - group] > a[j])
{
int temp = a[j];
k = j - group;
while (k>=0 && a[k]>temp)
{
a[k+group] = a[k];
k -= group;
}
a[k] = temp;
}
}
}
}
}
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
主要过程:
/*
1. 从数列中挑出一个元素作为基准数。
2. 重新排序数列,将比基准数大的放到右边,小于或等于它的数都放到左边。
3. 再对左右区间递归执行第二步,直至各区间只有一个数。
*/
// 不稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(n**2),辅助空间 O(logn)
int Paritition (int A[], int low, int high)
{
int 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;
}
void QuickSort(int A[], int low, int high) //快排母函数
{
if (low < high)
{
int pivot = Paritition1(A, low, high);
QuickSort(A, low, pivot - 1);
QuickSort(A, pivot + 1, high);
}
}
精简版
void QuickSort(vector &nums, int low, int high)
{
if(low < high)
{
int l = low, r = high, pivot = nums[low];
while(l=pivot) // 从右向左找第一个小于基准的数
{
r--;
}
nums[l] = nums[r];
while(l
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
/*
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
1.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
2.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
3.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
*/
// 不稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(n**2),辅助空间 O(1)
void adjustHeap(int nums[],int i,int length)
{
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;ktemp) //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
{
arr[i] = arr[k];
i = k;
}
else
{
break;
}
}
arr[i] = temp; //将temp值放到最终的位置
}
void HeapSort(int nums[],int len)
{
//1.构建大顶堆
for(int i=len/2-1;i>=0;i--)
{
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(nums,i,len);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=len-1;j>0;j--)
{
swap(nums[0],nums[j]);//将堆顶元素(最大值)与末尾元素进行交换,将最大值交换到数组的最后位置保存
adjustHeap(nums,0,j);//重新对堆进行调整
}
}