目录
排序的基本概念
插入排序
直接插入排序/折半插入排序
希尔排序
交换排序
冒泡排序
算法原理
性能
👩💻 快速排序
排序的基本概念
- 排序:将各元素按关键字递增/或递减顺序重新排列
- 评价指标
- 稳定性:关键字相同的元素经过排序后相对顺序是否会改变
- 时间复杂度、空间复杂度
- 分类
- 内部排序:数据都在内存中
- 外部排序:数据太多,无法全部放入内存
插入排序
直接插入排序/折半插入排序
- 算法思想:每次将一个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成。
- 直接插入排序:顺序查找找到插入的位置,适用于顺序表、链表
- 折半插入排序:折半查找找到应插入的位置,仅适用于顺序表
- 👩💻 注意:一直到low>high时才停止折半查找。当mid所指元素等于当前元素时,应继续令low = mid + 1,以保证“稳定性”。最终应将当前元素插入到low所指位置(即high + 1)
- 性能
- 空间复杂度 o(1)
- 时间复杂度
- 最好:原本有序O(n)
- 最坏:原本逆序O(n^2)
- 平均:O(n^2)
- 稳定性:稳定
希尔排序
- 先将待排序表分割成若干形如L[i,i+d,i+2d,…,i+kd]的“特殊”子表,对各个子表分别进行直接插入排序。缩小增量d,重复上述过程,直到d=1为止
- 性能
- 时间复杂度:当n在某个特定范围时,约为
- 空间复杂度:O(1)
- 稳定性:不稳定
- 适用性:仅可用于顺序表
- 👩💻 高频题型:给出增量序列,分析每一趟排序后的状态
交换排序
冒泡排序
算法原理
- 从后往前(或从前往后)两两比较相邻元素的值,若为逆序,则交换它们,直到序列比较完。称这样过程为“一趟”冒泡排序。最多只需n-1趟排序
- 每一趟排序都可以使一个元素的移动到最终位置,已经确定最终位置的元素在之后的处理中无需再对比
- 👩💻 如果某一趟排序过程中未发生“交换”,则算法可提前结束
性能
- 空间复杂度:O(1)
- 时间复杂度
- 最好O(n)——有序
- 最差——逆序
- 平均
- 稳定性:稳定
- 适用性:顺序表、链表都可以
👩💻 快速排序
void QuickSort(int A[],int low,int high){
if(low < high){ //递归跳出的条件
int pivotpos = Partition(A,low,high);//划分
QuickSort(A,low,pivotpos-1); //划分左子表
QuickSort(A,pivotpos+1,high); //划分右子表
}
}
//用第一个元素将待排序序列划分成左右两个部分
int Partition(int A[],int low,int high){
int pivot = A[low]; //第一个元素作为枢轴
while(low < high){ //用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; //返回存放枢轴的最终位置
}
- 算法思想:在待排序表L[1…n]中任取一个元素pivot作为枢轴(或基准,通常取首元素),通过一趟排序将待排序表划分为独立的两部分L[1…k-1]和L[k+1…n],使得L[1…k-1]中的所有元素小于pivot,L[k+1…n]中的所有元素大于等于pivot,则pivot放在了其最终位置L(k)上,这个过程称为一次“划分”。然后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置上。
- 算法表现主要取决于递归深度,若每次“划分”越均匀,则递归深度越低。“划分”越不均匀,则递归深度越深。
- 性能:
- 空间复杂度
- 最好:O(log2n)
- 最坏:O(n)
- 时间复杂度
- 最好:O(nlog2n)——每次划分很平均
- 最坏:O(n^2)——原本正序或逆序
- 平均:O(nlog2n)
- 稳定性:不稳定
- 空间复杂度