文章目录
排序算法基础:
排序是数据处理的基础,也是影响程序效率的重要组成因素。下面对常用的排序算法进行总结,并列举了面试中的遇到的部分问题:
理论基础:
博客园大牛笔记
个人代码实现:
#include <iostream>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
// 冒泡排序,从末尾逐一选择较小的元素存储到较前的位置,直至未排序的最前位置
void bubbleSort(vector<int> & source){
for(int i = 0; i < source.size(); i++){
for(int j = source.size()-1; j > i; j--){
if(source[j-1] > source[j]){
int tmp = source[j-1];
source[j-1] = source[j];
source[j] = tmp;
}
}
}
return;
}
// 插入排序(类似于打扑克,把后面的牌插入前面的牌中)
void Insertionsort(vector<int> & source)
{
//将按升序排列
int n=source.size();
for (int i=1;i<n;i++)
{
//将a[i]插入到a[i-1],a[i-2],a[i-3]……之中
for(int j=i;j>0&&source[j] < source[j-1];j--)
{
int temp = source[j];
source[j] = source[j-1];
source[j-1] = temp;
}
}
return;
}
// 选择排序,每次选择最小/最大的交换存放到前面(无序)
void SelectionSort(vector<int> & source){
for(int i = 0; i < source.size(); i++){
int minnum = i;
for(int j = i+1; j < source.size(); j++){
if(source[minnum] > source[j]){
minnum = j;
}
int tmp = source[i];
source[i] = source[minnum];
source[minnum] = tmp;
}
}
return;
}
// 快速排序
void fastranknum(vector<int> & source, int left, int right){
if(left>=right){
return;
}
int mid = (left + right)/2;
swap(source[mid], source[right]);
int small = left -1;
for(int i = left; i < right; i++){
if(source[i] < source[right]){
++small;
if(small != i) swap(source[small], source[i]);
}
}
++small;
swap(source[small], source[right]);
fastranknum(source, left, small);
fastranknum(source, small+1, right);
return;
}
// 归并排序
void remergeRanknum(vector<int> & source, int left, int right){
if(left>=right){
return;
}
int mid = (left + right)/2;
remergeRanknum(source, left, mid); // 归并左边
remergeRanknum(source, mid+1, right); // 归并右边
vector<int> nums(right-left+1, 0);
for(int index = left; index <= right; index++){
nums[index-left] = source[index];
}
int i =left, j = mid+1;
for(int index = left; index <= right; index++){
if(i > mid){
source[index] = nums[j-left];
j++;
}else if(j > right){
source[index] = nums[i-left];
i++;
}else if(nums[i-left] < nums[j-left]){
source[index] = nums[i-left];
i++;
}else{
source[index] = nums[j-left];
j++;
}
}
return;
}
// 希尔排序
void shellSort(vector<int> & source) {
int len = source.size();
for (int gap = len / 2; gap > 0; gap = gap / 2) {
// 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
for (int i = gap; i < len; i++) {
int j = i;
int current = source[i];
while (j - gap >= 0 && current < source[j - gap]) {
source[j] = source[j - gap];
j = j - gap;
}
source[j] = current;
}
}
return;
}
// 堆排序子过程
void max_heapify(vector<int> &source, int start, int end)
{
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end) //若子节点指标在范围内才做比较
{
if (son + 1 <= end && source[son] < source[son + 1]) //先比较两个子节点大小,选择最大的
son++;
if (source[dad] > source[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
return;
else //否则交换父子内容再继续子节点和孙节点比较
{
swap(source[dad], source[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
// 堆排序
void heap_sort(vector<int> & source)
{
int len = source.size();
//初始化,i从最後一个父节点开始调整
for (int i = len / 2 - 1; i >= 0; i--)
max_heapify(source, i, len - 1);
//先将第一个元素和已经排好的元素前一位做交换,再从新调整(刚调整的元素之前的元素),直到排序完毕
for (int i = len - 1; i > 0; i--)
{
swap(source[0], source[i]);
max_heapify(source, 0, i - 1);
}
}
// 计数排序 1)根据排序的最大和最小值之差,计算出计数区间;2)统计各个字段的值,然后遍历区间,把根据从小到大的顺序把数保存起来
void countSort(vector<int> & source){
int vecMin = INT_MAX, vecMax = INT_MIN;
for(int i = 0; i < source.size(); i++){
source[i] < vecMin?vecMin = source[i]:vecMin;
source[i] > vecMax?vecMax = source[i]:vecMax;
}
vector<int> keep(vecMax-vecMin+1,0);
for(int i = 0; i < source.size(); i++){
keep[source[i]-vecMin]++;
}
int j = 0;
for(int i = 0; i < keep.size(); i++){
while(keep[i]){
source[j] = i+vecMin;
j++;
keep[i]--;
}
}
}
// 桶排序 在计数排序的基础上,进行了部分优化,缩短了统计区间,并用插入排序对小区间进行排序
void bucketSort(vector<int> & source, int bucketSize =10){ // source排序数组,bucketSize桶的大小
int vecMin = INT_MAX, vecMax = INT_MIN;
bucketSize = bucketSize;
for(int i = 0; i < source.size(); i++){
source[i] < vecMin?vecMin = source[i]:vecMin;
source[i] > vecMax?vecMax = source[i]:vecMax;
}
int bucketCount = (vecMax - vecMin) / bucketSize + 1;
vector<vector<int>> keep(bucketCount);
for(int i = 0; i < source.size(); i++){
keep[(source[i]-vecMin)/bucketSize].push_back(source[i]);
}
int j = 0;
for(int i = 0; i < keep.size(); i++){
Insertionsort(keep[i]);
for(int k = 0; k < keep[i].size(); k++){
source[j] = keep[i][k];
j++;
}
}
}
// 基数排序 从个位到最高位依次从0-9进行排序
void radixSort(vector<int> & source) {
int vecMax = INT_MIN;
vector<vector<int> > counter(10);
for(int i = 0; i < source.size(); i++){
source[i] > vecMax?vecMax = source[i]:vecMax;
}
int maxDigit = 0;
int nCount = vecMax;
while(nCount){
maxDigit++;
nCount = nCount/10;
}
int mod = 10;
int dev = 1;
for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { // 从个位到最高位
for(int j = 0; j < source.size(); j++) { // 记录0-9位数的值
int bucket = (source[j] % mod) / dev;
counter[bucket].push_back(source[j]);
}
int pos = 0;
for(int j = 0; j < counter.size(); j++) {
for(int k = 0; k < counter[j].size(); k++){
source[pos++] = counter[j][k];
}
counter[j].clear();
}
}
return;
}
int main(){
vector<int> vec = {1,23,232,3131,1313,3131,3134,3131,4,13,31,41,313,3133,3131,67,41,78,69,48};
cout<<"原数组: ";
for(int i = 0; i < vec.size(); i++){
cout<<vec[i]<<" ";
}
cout<<endl;
string algorUsed;
cin>>algorUsed;
if(!strcmp(algorUsed.c_str(), "bubble")){ // 冒泡排序
bubbleSort(vec);
}else if(!strcmp(algorUsed.c_str(), "insert")){ // 插入排序
Insertionsort(vec);
}else if(!strcmp(algorUsed.c_str(), "select")){ // 选择排序
SelectionSort(vec);
}else if(!strcmp(algorUsed.c_str(), "fast")){ // 快速排序
fastranknum(vec, 0, vec.size());
}else if(!strcmp(algorUsed.c_str(), "remerge")){ // 归并排序
remergeRanknum(vec, 0, vec.size());
}else if(!strcmp(algorUsed.c_str(), "shell")){ // 希尔排序
shellSort(vec);
}else if(!strcmp(algorUsed.c_str(), "heap")){ // 堆排序
heap_sort(vec);
}else if(!strcmp(algorUsed.c_str(), "count")){ // 计数排序
countSort(vec);
}else if(!strcmp(algorUsed.c_str(), "bucket")){ // 桶排序
bucketSort(vec);
}else if(!strcmp(algorUsed.c_str(), "radix")){ // 基数排序
radixSort(vec);
}else{
cout<<"没有输入合适的算法,该数组暂未排序";
}
for(int i = 0; i < vec.size(); i++){
cout<<vec[i]<<" ";
}
system("pause");
return 0;
}
STL的sort排序是怎么实现的:
sort采用快速排序+插入排序+堆排序的方法来实现的,首先采用快速排序把数组分段,当数据量到达某个阈值(16)时,采用插入排序来减少继续分割带来的过大开销,为避免递归层次过深,还会用到堆排序来优化。
stl的实现原理介绍
扩展题:
一个数组:source = [2,0,3,12,0],target = [2,3,12,0,0]。实现把数组在原来位置相对不变的情况下,把0移至最后。
思路:采用插入排序,从末尾遍历数组,遇到0,则把它插入到最后一个非0的位置。
#inculde<iostream>
using namespace std;
int main(){
vector<int> target = {2,0,3,12,0};
int count = target.size()-1;
for(int i = target.size()-1; i >= 0; i--){
if(target[i] == 0 && i != target.size()-1){
for(int j = i; j <= count; j++){
target[j] = target[j+1];
}
target[count] = 0;
count--;
}
}
for(int i = 0; i < target.size(); i++){
cout<<target[i]<<" ";
}
system("pause");
return 0;
}