系列综述:
💞目的:本系列是个人整理为了秋招算法
的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于代码随想录
进行的,每个算法代码参考leetcode高赞回答和其他平台热门博客,其中也可能含有一些的个人思考。
🤭结语:如果有帮到你的地方,就点个赞和关注一下呗,谢谢🎈🎄🌷!!!
🌈【C++】秋招&实习面经汇总篇🌈
😊点此到文末惊喜↩︎
无序
的记录序列调整为有序
的记录序列存放在内存
中所进行的排序过程,适合不太大的元素序列。存储在外存储器
上,通常待排序的文件无法一次装入内存。某种算法
迭代,将无序区的最值添加到有序区后面直冒简希,快堆二基
算法种类 | 最好情况 | 平均情况 | 最坏情况 | 空间复杂度 | 是否稳定 |
---|---|---|---|---|---|
直接插入排序 | O(n)O(n)O(n) | O(n2)O(n^2)O(n2) | O(n2)O(n^2)O(n2) | O(1)O(1)O(1) | 是 |
冒泡排序 | O(n)O(n)O(n) | O(n2)O(n^2)O(n2) | O(n2)O(n^2)O(n2) | O(1)O(1)O(1) | 是 |
简单选择排序 | O(n2)O(n^2)O(n2) | O(n2)O(n^2)O(n2) | O(n2)O(n^2)O(n2) | O(1)O(1)O(1) | 否 |
希尔排序 | 适合大规模数据 | O(n1.3)O(n^{1.3})O(n1.3) | O(n2)O(n^2)O(n2) | O(1)O(1)O(1) | 否 |
快速排序 | O(nlog2n)O(nlog_2n)O(nlog2n) | O(nlog2n)O(nlog_2n)O(nlog2n) | O(n2)O(n^2)O(n2) | O(log2n)O(log_2n)O(log2n) | 否 |
堆排序 | O(nlog2n)O(nlog_2n)O(nlog2n) | O(nlog2n)O(nlog_2n)O(nlog2n) | O(nlog2n)O(nlog_2n)O(nlog2n) | O(1) | 否 |
2路归并排序 | O(nlog2n)O(nlog_2n)O(nlog2n) | O(nlog2n)O(nlog_2n)O(nlog2n) | O(nlog2n)O(nlog_2n)O(nlog2n) | O(n)O(n)O(n) | 是 |
基数排序 | O(d(n+r))O(d(n+r))O(d(n+r)) | O(d(n+r))O(d(n+r))O(d(n+r)) | O(d(n+r))O(d(n+r))O(d(n+r)) | O(r)O(r)O(r) | 是 |
待补充··· |
void insertSort(vector &nums){// 第一个元素认为已经排序完,共进行n-1轮for (int i = 1; i < nums.size(); ++i){int flag = nums[i]; // 将无序区第一个元素作为待排序元素// 从后向前遍历有序区,找到合适位置插入待排序元素for (int j = i; j >= 0; --j){if (nums[j - 1] > flag){nums[j] = nums[j - 1];}else{// 插入即结束本次迭代nums[j] = flag;break;}}}
}
交换排序
,每次迭代中会有一个数据元素像小气泡一样慢慢上升(下降)到有序区void bullbleSort(vector &nums){int n = nums.size();// n个数据元素只需要n-1次排序,因为排完最后一个元素已经有序for(int i = 0; i < n-1; ++i){flag = false;// 发生交换的标志// 每次将无序区间最小的数据元素放到有序区的后面for(int j = n-1; j > i; --j){if(nums[j] < nums[j-1]){swap(nums[j-1], nums[j]);flag = true;}// 本次遍历没有发生交换,说明已经有序if(flag == false)return ;}}
}
void selectSort(vector &nums){int select = 0; // 每次迭代记录无序区中最小的数的下标// 从第一个数开始迭代n-1次,最后一次末尾的两个数值一起排序完成for (int i = 0; i < nums.size() - 1; ++i){// 每次更新最小值下标为初始值select = i;// 从无序区中找到最小值的下标for (int j = i; j < nums.size() - 1; ++j){if (nums[j] < nums[select]){select = j;}}// 交换有序区的后一个和无序区中最小的那个swap(nums[i], nums[select]);}
}
void shell_sort(int arr[], int len) {int gap, i, j;int temp;for (gap = len >> 1; gap > 0; gap >>= 1)for (i = gap; i < len; i++) {temp = arr[i];for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap)arr[j + gap] = arr[j];arr[j + gap] = temp;}
}
void QuickSort(vector &nums, int left, int right){
// 递归出口
if (left >= right)return;int low = left;
int high = right;
// 选第一个元素为枢纽
int pivot = low;
while (low < high){// 从后向前找比枢纽小的while (nums[high] >= nums[pivot] && low < high){--high;}// 从前向后找比枢纽大的while (nums[low] <= nums[pivot] && low < high){++low;}// 交换swap(nums[low], nums[high]);
}
swap(nums[pivot], nums[high]);
pivot = high;
// 分治[left, pivot+1] pivot [pivot+1, right]
QuickSort(nums, left, pivot - 1);
QuickSort(nums, pivot + 1, right);
}
完全二叉树
中,所有根均大于
左右子树的值。完全二叉树
中,所有根均小于
左右子树的值。dad * 2 + 1
,右孩子为dad * 2 + 1+1
void max_heapify(int arr[], int start, int end) {//建立父节点指标和子节点指标int dad = start;int son = dad * 2 + 1;// 从0开始计数,所以加一while (son <= end) { //若子节点指标在范围内才做比较if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的son++;if (arr[dad] > arr[son]) //如果父节点大于子节点代表调整完毕,直接跳出函数return;else { //否则交换父子内容再继续子节点和孙节点比较swap(arr[dad], arr[son]);dad = son;son = dad * 2 + 1;}}
}
void heap_sort(int arr[], int len) {//初始化,i从最后一个父节点开始调整for (int i = len / 2 - 1; i >= 0; i--)max_heapify(arr, i, len - 1);//先将第一个元素和已经排好的元素前一位做交换,再从新调整(刚调整的元素之前的元素),直到排序完毕for (int i = len - 1; i > 0; i--) {swap(arr[0], arr[i]);max_heapify(arr, 0, i - 1);}
}
原理:采用分治法的思想
两个
子序列合并,得到完全有序的新序列优化思路
算法
// 分治法:先划分后合并
void mergeSort(ElemType A[],int low,int high){// 当数组被划分成单独的元素,则low>=high时跳出递归if(low < high){ //划分规则 中点 int mid = (low + high)/2; mergeSort(A,low,mid);mergeSort(A,mid+1,high);//一次划分 一次合并merge(A,low,mid,high); }
} // 合并函数:将A[low..mid] 和 A[mid+1...high]进行合并
void merge(ElemType A[],int low,int mid,int high){//B里暂存A的数据 for(int k = low ; k < high + 1 ; k++){B[k] = A[k]; } /*这里对即将合并的两个数组 *A[low..mid] 头元素 A[i]和 A[mid+1...high] 头元素 A[j] *进行一个头部的标记, 分别表示为数组片段的第一个元素 *k 是目前插入位置。 */ int i = low , j = mid + 1 , k = low; //只有在这种情况下 才不会越界 while(i < mid + 1 && j < high + 1) {//A的元素暂存在B里,因为不能再A上原地操作,会打乱数据//这也是为什么二路归并排序(合并排序)空间复杂度是O(n)的原因 //我们这里把值小的放在前面,最后排序结果就是从小到大 if(B[i] > B[j]){A[k++] = B[j++]; }else{A[k++] = B[i++]; } } //循环结束后,会有一个没有遍历结束的数组段。处理上文的情况2while(i < mid + 1) A[k++] = B[i++]; while(j < high + 1) A[k++] = B[j++];
}
int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{int maxData = data[0]; ///< 最大数/// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。for (int i = 1; i < n; ++i){if (maxData < data[i])maxData = data[i];}int d = 1;int p = 10;while (maxData >= p){//p *= 10; // Maybe overflowmaxData /= 10;++d;}return d;
/* int d = 1; //保存最大的位数int p = 10;for(int i = 0; i < n; ++i){while(data[i] >= p){p *= 10;++d;}}return d;*/
}
void radixsort(int data[], int n) //基数排序
{int d = maxbit(data, n);int *tmp = new int[n];int *count = new int[10]; //计数器int i, j, k;int radix = 1;for(i = 1; i <= d; i++) //进行d次排序{for(j = 0; j < 10; j++)count[j] = 0; //每次分配前清空计数器for(j = 0; j < n; j++){k = (data[j] / radix) % 10; //统计每个桶中的记录数count[k]++;}for(j = 1; j < 10; j++)count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中{k = (data[j] / radix) % 10;tmp[count[k] - 1] = data[j];count[k]--;}for(j = 0; j < n; j++) //将临时数组的内容复制到data中data[j] = tmp[j];radix = radix * 10;}delete []tmp;delete []count;
🚩点此跳转到首行↩︎
上一篇:安装flume