#include<iostream>
void baseSort(int arr[], int len); // 基数排序
void baseCountSort(int arr[],int divide,int len);
void countSort(int arr[], int len); // 计数排序
void heapSort(int arr[],int len); //堆排序
void makeHeap(int arr[],int len);
void heapify(int arr[], int index, int rear);
void quickSort(int arr[],int left,int right); // 快速排序
// 归并排序
void guibing(int arr[],int left,int right,int temp[]);
void emerge(int arr[],int left,int middle,int right,int temp[]);
void xier(int arr[],int len); // 希尔排序
void insertSort(int arr[], int len); // 插入排序
void choseSort(int arr[],int len); // 选择排序
void maopao(int arr[],int len);// 普通冒泡
void smaopao(int arr[], int len);// 双向冒泡
void input(int arr[], int len);
void swap(int *a,int *b);
using namespace std;
int main() {
int arr1[] = {8, 9, 1, 2, 0, 4};
// 普通冒泡
maopao(arr1,6);
input(arr1,6);
int arr2[] = {8, 9, 1, 2, 0, 4};
// 双向冒泡
smaopao(arr2,6);
input(arr2,6);
// 选择排序
int arr3[] = {8, 9, 1, 2, 0, 4};
choseSort(arr3,6);
input(arr3,6);
// 选择排序
int arr4[] = {8, 9, 1, 2, 0, 4};
insertSort(arr4,6);
input(arr4,6);
// 希尔排序
int arr5[] = {8, 9, 1, 2, 0, 4};
xier(arr5,6);
input(arr5,6);
// 归并排序
int arr6[] = {8, 9, 1, 2, 0, 4};
int temp[6];
guibing(arr6,0,5,temp);
input(arr6,6);
// 快速排序
int arr7[] = {8, 9, 1, 2, 0, 4};
quickSort(arr7,0,5);
input(arr7,6);
//堆排序
int arr8[] = {8, 9, 1, 2, 0, 4};
heapSort(arr8,6);
input(arr8,6);
//计数排序
int arr9[] = {8, 9, 1, 2, 0, 4};
countSort(arr9,6);
input(arr9,6);
//基数排序
int arr10[] = {108, 9, 11, 2, 10, 4};
baseSort(arr10,6);
input(arr10,6);
return 0;
}
/**
* 20210804 基数排序
* 思路:
(1)基数排序,最小值:0,首先先找到序列最大值
(2)依据最大值的位数,分别对:个、十、 百、千....进行计数排序
* 降序:2,4,9,10,11,108
*/
void baseSort(int arr[], int len) {
int max = arr[0];
for(int i = 0 ; i < len ; i++) {
if(max < arr[i]) {
max = arr[i];
}
}
for(int divide = 1; divide <= max; divide *= 10) {
baseCountSort(arr, divide, len);
}
}
void baseCountSort(int arr[],int divide,int len) {
int count[10];
for(int i = 0; i < 10; i++){
count[i] = 0;
}
for(int i = 0; i < len ; i++){
count[arr[i]/divide%10 - 0]++;
}
for(int i = 1; i < 10; i++){
count[i] += count[i - 1];
}
int temp[len];
for(int i = 0; i < len; i++){
temp[i] = 0;
}
// 反向填充
for(int i = len - 1; i >= 0; i--){
temp[--count[arr[i]/divide%10]] = arr[i];
}
for(int i = 0; i < len; i++) {
arr[i] = temp[i];
}
}
/**
* 20210803 计数排序(用于序列中最大元素不是很大的序列)
* 思路:
(1)找到待排序数组的最大值和最小值
(2)创建一个计数数组(max-min+1)
(3)统计待排序数组中每个元素出现的次数,存入计数数组中
(4)对所有元素出现的次数累加
(5)方向填充目标数组
* 降序:9,8,4,2,1,0
*/
void countSort(int arr[], int len) {
int min = arr[0];
int max = arr[0];
for(int i = 0; i < len; i++) {
if(arr[i] < min) {
min = arr[i];
}
if(arr[i] > max) {
max = arr[i];
}
}
int count_len = max - min + 1;
int count[count_len];
for(int i = 0; i < count_len; i++) {
count[i] = 0;
}
for(int i = 0; i < len; i++) {
count[arr[i] - min]++;
}
// 累加
for(int i = 1; i < count_len; i++) {
count[i] += count[i-1];
}
// 临时数组存入已排序好的数组
int temp[len];
for(int i = 0; i < len ; i++) {
temp[i] = 0;
}
for(int i = len - 1; i >= 0; i--) {
temp[--count[arr[i] - min]] = arr[i];
}
for(int i = 0; i < len; i++) {
arr[i] = temp[i];
}
}
/**
* 20210803 堆排序
* 思路:
(1)将无序序列构造成一个大顶推
(2)固定一个最大值(顶元素与最后一个元素交互),固定好的元素将不再参与排序
(3)对于剩下元素,依次构造,直到堆的尺寸为:1
* 降序:0,1,2,4,8,9
<pre>
heapSort(arr,len);
</pre>
*/
void heapSort(int arr[],int len) {
// 先构建大根堆(元素上升)
makeHeap(arr,len);
// 尾指针,初始指向末尾
int rear = len;
while(rear > 0) {
// 固定好最大值,因为已经构造好了:大顶推,这里将顶元素与末尾元素交换
swap(arr[0],arr[rear-1]);
// 固定好一个,则尾指针向前移动一位
rear--;
// 对剩余元素继续构建大顶推(元素下降:从根节点触发)
heapify(arr,0,rear);
}
}
// 元素上升,从低向上
void makeHeap(int arr[],int len) {
for(int i = 0; i < len; i++) {
int currentIndex = i;
// currentIndex-1,考虑到当前节点为根节点时:(0-1)/2 = 0
int fatherIndex = (currentIndex - 1) / 2;
while(arr[currentIndex] > arr[fatherIndex]) {
// 若当前节点比它父节点大,则交换
swap(&arr[currentIndex], &arr[fatherIndex]);
currentIndex = fatherIndex;
// 重新计算父节点
fatherIndex = (currentIndex - 1) / 2;
}
}
}
// 元素下降,从根节点出发(构建大顶堆:升序)
void heapify(int arr[], int index, int rear) {
// 计算左右孩子节点
int left = 2 * index + 1;
int right = 2 * index + 2;
// 遍历剩下所有元素 (将父以及左右孩子节点调整为:父节点放置三者最大(或最小)元素
while(left < rear) {
int tempIndex = 0; // 记录最大(最小)元素下标
if(right < rear && arr[left] < arr[right]) {
tempIndex = right;
} else {
tempIndex = left;
}
// 跟父节点比较
if(arr[index]>arr[tempIndex]) {
tempIndex = index;
}
// 若父节点是最大的,则结束循环
if(index == tempIndex) {
break;
}
swap(&arr[index],&arr[tempIndex]);
// 更新父节点下标,并计算其左右孩子下标位
index = tempIndex;
left = 2 * index + 1;
right = 2 * index + 2;
}
}
/**
* 20210803 快速排序
* 思路:递归分治
(1)选择基准数(随意挑选,一般默认:第一个)
(2)通过一趟排序,以基准数为中心,使序列分割成两部分( 基准数左边的都是小于它,右边的则都大于它)
(3)重复这个过程,直到序列只有一个元素或者空(递归出口)
* 降序:9,8,4,2,1,0
*/
void quickSort(int arr[],int left,int right) {
// 递归出口
if(left >= right) {
return;
}
// 左指针
int first = left;
// 右指针
int end = right;
// 基准数
int key = arr[first];
// 前后指针都往中间移动,两者越过对方时,循环终止
while(first < end) {
// 必须先从右向左比较,找到一个小于基准数的元素
while(first < end && arr[end] <= key) {
end--;
}
arr[first] = arr[end];
while(first < end && arr[first] >= key) {
first++;
}
arr[end] = arr[first];
}
// 遍历完后,就可以确认基准数的位置
arr[first] = key;
// 以基准数为间隔点,将其拆分为两个序列(不包括基准数),再对其快排
quickSort(arr,left,first - 1);
quickSort(arr,first + 1,right);
}
/**
* 20210803 归并排序
* 思路:分而治之
(1)将序列通过递归划分左右序列,直到left<right不满足时,则开始对划分的左右序列排序并合并
* 降序:9,8,4,2,1,0
*/
void guibing(int arr[],int left,int right,int temp[]) {
if(left < right) {
int middle = (left + right) / 2;
guibing(arr,left,middle,temp);
guibing(arr,middle+1,right,temp);
emerge(arr,left,middle,right,temp);
}
}
/**
* 归并排序,排序和合并
(1)获取两个序列的起始位
(2)循环比较两个序列,将比较结果放置临时数组中
(3)若某序列还有剩余元素,则将其放到临时数组后面
(4)将比较好的临时数组全部赋值给arr原数组
(5)依次递归处理
*/
void emerge(int arr[],int left,int middle,int right,int temp[]) {
int i = left;
int j = middle+1;
int tempIndex = 0;
while(i <= middle&&j <= right) {
if(arr[i] > arr[j]) {
temp[tempIndex++] = arr[i++];
} else {
temp[tempIndex++] = arr[j++];
}
}
while(i <= middle) {
temp[tempIndex++] = arr[i++];
}
while(j <= right) {
temp[tempIndex++] = arr[j++];
}
tempIndex = 0;
while(left <= right) {
arr[left++] = temp[tempIndex++];
}
}
/**
* 20210803 希尔排序(分组插入排序)
* 思路:
(0)以某个增量将序列分成若干个序列,然后依次缩进增量,再进行排序,直到只有一组序列后,再排序一次,即可
(1)将第一个元素看成有序系列,第二个到最后一个看成未排序系列
(2)从头扫描未排序系列,将扫描的元素依次插入到有序序列合适的位置
(3)若相等,则插入到相等元素后面
* 升序:0,1,2,4,8,9
*/
void xier(int arr[],int len) {
// 增量:length/2
for(int gap = len/2; gap > 0; gap=gap/2) {
// 以gap间隔将序列分为gap组,i=gap:某组第二个元素位置
for(int i = gap; i < len; i++) {
// j就是下标位,这不记录前有多少个有序元素
int j = i;
int key = arr[j];
if(arr[j] < arr[j-gap]) {
while(j - gap >= 0 && key < arr[j-gap]) {
// 向后移
arr[j] = arr[j-gap];
// j向前移,若下次循环不满足,则当前位置就是插入位
j = j - gap;
}
}
arr[j] = key;
}
}
}
/**
* 20210803 插入排序
* 思路:
(1)将第一个元素看成有序系列,第二个到最后一个看成未排序系列
(2)从头扫描未排序系列,将扫描的元素依次插入到有序序列合适的位置
(3)若相等,则插入到相等元素后面
* 升序:0,1,2,4,8,9
*/
void insertSort(int arr[], int len) {
for(int i = 1; i < len; i++) {
// 获取有序序列的个数(由于下班从0开始,这里减一
int j = i - 1;
int key = arr[i];
while( j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
// 当前元素在有序序列位置,j+1:当j位不合法时,则要倒退一位
arr[j+1] = key;
}
}
/**
* 20210803 选择排序
* 思路:
(1)从未排序的系列中找到最小(最大)元素放置到排序系列的起始
(2)循环,从未排序的系列中找到最小(最大)元素放置到排序系列的末尾
* 升序:0,1,2,4,8,9
*/
void choseSort(int arr[],int len) {
for(int i = 0; i < len - 1; i++) {
int minIndex = i;
// j < len:每个元素都要比较,取最小,冒泡排序小于len-1,是因为前后比较,最后一次比较包含最后一个元素
for(int j = i + 1; j < len; j++) {
if(arr[minIndex] > arr[j]) {
minIndex = j;
}
}
swap(&arr[minIndex],&arr[i]);
}
}
/**
* 20210803 双向冒泡排序
* 升序:0,1,2,4,8,9
*/
void smaopao(int arr[], int len) {
for(int i = 0; i < len - 1; i++) {
for(int j = 0, k = len - i - 1; j < len - i - 1; j++, k--) {
if(arr[j] > arr[j+1]) { // 自左向右
swap(&arr[j],&arr[j+1]);
}
if(arr[k] < arr[k - 1]) { // 自右向左
swap(&arr[k],&arr[k-1]);
}
}
}
}
/**
* 20210803 冒泡排序
* 升序:0,1,2,4,8,9
*/
void maopao(int arr[],int len) {
for(int i = 0; i < len - 1; i++) {
for(int j = 0; j < len - i - 1; j++) {
if(arr[j] > arr[j+1]) {
swap(&arr[j],&arr[j+1]);
}
}
}
}
// 两数交换
void swap(int *a,int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 打印输出
void input(int arr[], int len) {
for(int i = 0; i < len; i++) {
cout<<arr[i]<<" ";
}
cout<<endl;
}
03-17
2万+
04-14
2433
06-10
230