冒泡排序两个两个看交换位置 每一轮都会有最大的泡泡找到他的位置 需要进行n轮 稳定
插入排序打扑克摸牌 顺序插入 摸n张牌 每次都得遍历 所以。。 稳定
最好情况按顺序来的 O(n)
选择排序 选出最小的放第一个位置(与第一个位置交换) 然后从第二个数开始判断再选出最小的放第一个位置
选出最小的2 然后2和3交换 两个3的相对位置变了 所以不稳定
快排 不稳定 最坏情况 每次选到最大的数作为标准 那么就得操作n层
归并 稳定
快速排序:QuickSort
选标准值,将比标准值小的放在其左侧,将比标准值大的放在其右侧,左右两部分分别重复以上操作
1.挖坑填补法
拆东墙补西墙
先把第一个数拿出来用temp储存 然后从最后面遍历 找到比temp小的放到第一个位置 然后再从前面第二个开始遍历找比temp大的放在后面的空位上 重复操作 直到end和begin在一块 然后再在temp两边分别重复操作
#include<stdio.h>
int Find(int arr[],int nBegin,int nEnd)
{
int temp = arr[nBegin];
while(nBegin < nEnd)
{
//从后向前找比标准值小的
while(nEnd > nBegin)
{
if(arr[nEnd] < temp)
{
arr[nBegin] = arr[nEnd];
nBegin++;
break;
}
nEnd--;
}
//从前往后找比标准值大的
while(nBegin < nEnd)
{
if(arr[nBegin] > temp)
{
arr[nEnd] = arr[nBegin];
nEnd--;
break;
}
nBegin++;
}
}
//标准值放入
arr[nBegin] = temp;
return nBegin;
}
void QuickSort(int arr[],int nBegin,int nEnd)
{
if(arr == NULL || nBegin >= nEnd)return;
//确定标准值最终位置
int nStandard;
nStandard = Find(arr,nBegin,nEnd);
//将数据分成两部分 分别重复以上操作
QuickSort(arr,nBegin,nStandard-1);
QuickSort(arr,nStandard+1,nEnd);
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
QuickSort(arr,0,sizeof(arr)/sizeof(arr[0])-1);
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
2.区间分割法
small指向begin-1 begin从前向后遍历 遇见比end小的 就交换small+1与begin 最终将小于10的全放在一边
若 a = i++; 则等价于 a=i;i=i+1; 而 a = ++i; 则等价于 i=i+1;a=i;
#include<stdio.h>
int Find(int arr[],int nBegin,int nEnd)
{
int nSmall = nBegin-1;
for(nBegin;nBegin < nEnd;nBegin++)
{
if(arr[nBegin] < arr[nEnd])
{
if(++nSmall != nBegin)
{
arr[nSmall] = arr[nSmall]^arr[nBegin];
arr[nBegin] = arr[nSmall]^arr[nBegin];
arr[nSmall] = arr[nSmall]^arr[nBegin];
}
}
}
//将标准值放入
if(++nSmall != nEnd)
{
arr[nSmall] = arr[nSmall]^arr[nEnd];
arr[nEnd] = arr[nSmall]^arr[nEnd];
arr[nSmall] = arr[nSmall]^arr[nEnd];
}
return nSmall;
}
void QuickSort(int arr[],int nBegin,int nEnd)
{
if(arr == NULL || nBegin >= nEnd)return;
//确定标准值最终位置
int nStandard;
nStandard = Find(arr,nBegin,nEnd);
//将数据分成两部分 分别重复以上操作
QuickSort(arr,nBegin,nStandard-1);
QuickSort(arr,nStandard+1,nEnd);
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
QuickSort(arr,0,sizeof(arr)/sizeof(arr[0])-1);
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
快排的非递归
【数据结构与算法篇】手撕八大排序算法之快排的非递归实现及递归版本优化(三路划分)-阿里云开发者社区 (aliyun.com)
非递归实现 因为递归深度太深可能会导致栈溢出,可以使用栈来模拟递归
首先把整个数组的最右侧下标 也就是右区间入栈 再将左区间入栈 (因为取的时候就可以先取左区间,再取右区间,然后while循环栈不为空 每次取出一个左右区间 然后把整个左右区间放进Partition里面 他就会返回一个数组下标 下标左边的都比他小 下标右边的都比他大 这时候数组就被划分为两部分 再把这两部分 也就是四个下标放进栈中 然后循环下一轮 取出栈顶的一个区间再进行划分 直到区间大小为1 比如说【2,3】 就不用再划分了
void Swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//hoare版本
int Partition1(int* a, int left, int right)
{
int keyi = left;
while (left < right)
{
//注意: 要加上left < right 否则会出现越界
//若不判断等于基准值,也会出现死循环的情况
//右边找小
while (left < right && a[right] >= a[keyi])
{
right--;
}
//左边找大
while (left < right && a[left] <= a[keyi])
{
left++;
}
Swap(&a[left], &a[right]);
}
Swap(&a[left], &a[keyi]);
return left;
}
void QuicksortNonR(int* a, int begin, int end)
{
Stack st;
StackInit(&st);
//注意栈的顺序是后进先出,需要倒着放进去,正着拿出来
//将排序数组的起始和末端下标入栈
StackPush(&st, end);
StackPush(&st, begin);
//栈不为空一直循环
while (!StackEmpty(&st))
{
//弹出子区间(左右两个下标)
int left = StackTop(&st);
StackPop(&st);
int right = StackTop(&st);
StackPop(&st);
//执行分区操作
int keyi = Partition1(a, left, right);
//[left,keyi - 1] keyi [keyi + 1, right]
//注意只剩一个数或区间不存在则停止入栈
if (keyi + 1 < right)
{
StackPush(&st,right);
StackPush(&st,keyi + 1);
}
if (left < keyi - 1)
{
StackPush(&st, keyi - 1);
StackPush(&st, left);
}
}
}
void PrintArray(int* a, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
int main()
{
int a[] = { 9,6,7,1,4,5,5,2,10,1,6,3,7 };
QuicksortNonR(a, 0, sizeof a / sizeof(int) - 1);
PrintArray(a, sizeof a / sizeof(int));
}
MergeSort: 归并排序
将多个有序数组进行合并
排序算法:归并排序【图解+代码】_哔哩哔哩_bilibili
首先用递归的思想 分成各个小块 一半一半分
然后再两个两个合在一起
两个数组用两个指针比大小
小的放前面
nlogn
稳定不稳定看你怎么写
小于等于稳定 小于是不稳定的
#include<stdio.h>
#include<stdlib.h>
void Merge(int arr[],int nBegin,int nEnd)
{
int nBegin1 = nBegin;
int nEnd1 = nBegin+(nEnd-nBegin)/2;
int nBegin2 = nEnd1+1;
int nEnd2 = nEnd;
int *pTemp =NULL;
pTemp = (int*)malloc(sizeof(int)*(nEnd-nBegin+1));
int i=0;
//遍历两个数组
while(nBegin1 <= nEnd1 && nBegin2 <= nEnd2)
{
if(arr[nBegin2] < arr[nBegin1])
{
pTemp[i++] = arr[nBegin2++];
}
else
{
pTemp[i++] = arr[nBegin1++];
}
}
//将有剩余的数组元素放置
while(nBegin1 <= nEnd1)
{
pTemp[i++] = arr[nBegin1++];
}
while(nBegin2 <= nEnd2)
{
pTemp[i++] = arr[nBegin2++];
}
//放回
for(int i=0;i<nEnd-nBegin+1;i++)
{
arr[nBegin+i] = pTemp[i];
}
free(pTemp);
pTemp = NULL;
}
void MergeSort(int arr[],int nBegin,int nEnd)
{
if(arr == NULL || nBegin >= nEnd)return;
//分割
int nMid = nBegin + (nEnd-nBegin)/2;
MergeSort(arr,nBegin,nMid);
MergeSort(arr,nMid+1,nEnd);
//合并
Merge(arr,nBegin,nEnd);
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
MergeSort(arr,0,sizeof(arr)/sizeof(arr[0])-1);
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
冒泡排序:BubbleSort
相邻两个元素进行大小比较,如果前一个比后一个大,则二者发生交换
第一横:8和6比 8比6大 交换 8和3比 8比3大 交换 8和12比 没12大 不动 12和1比 比12大交换 12和7比 比12大交换 12没15大 不动
第二横;6和3比。。。。。。。
#include<stdio.h>
void BubbleSort(int arr[],int length)
{
if(arr == NULL || length<=0)return;
int i;
int j;
for(int i=0;i<length-1;i++) //总排n-1回
{
for(int j=0;j<length-i-1;j++) //每次固定一个大的,然后俩俩比较再-1
{
if(arr[j] > arr[j+1])
{
arr[j] = arr[j]^arr[j+1];
arr[j+1] = arr[j]^arr[j+1];
arr[j] = arr[j]^arr[j+1];
}
}
}
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
BubbleSort(arr,sizeof(arr)/sizeof(arr[0]));
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
堆排序:HeapSort
#include<iostream>
using namespace std;
void print_arr(int arr[], int n) {
for (int i = 0; i < n; i++) {
cout << " " << arr[i];
}
cout<<endl;
}
void swap(int * a, int * b) {
int temp = * a;
* a = * b;
* b = temp;
}
/*
arr 存贮数组
n 数组长度
i 代维护节点下标
*/
void heapify(int arr[], int n, int i) {
int largest = i;
int lson = i * 2 + 1;
int rson = i * 2 + 2;
if (lson < n && arr[largest] < arr[lson])
largest = lson;
if (rson < n && arr[largest] < arr[rson])
largest = rson;
if (largest != i) {
swap( & arr[largest], & arr[i]);
heapify(arr, n, largest);
}
}
//堆排序入口
void heap_sort(int arr[], int n) {
//建堆
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
//排序
for (int i = n - 1; i >= 0; i--) {
swap( & arr[i], & arr[0]);
heapify(arr, i, 0);
}
}
int main() {
int arr[] = { 2,3,8,1,4,9,10,7,16,14 };
int n = 10;
print_arr(arr, n);
heap_sort(arr, n);
print_arr(arr, n);
return 0;
}
首先先建立一个初始堆 从最后一个父节点开始建堆
具体的建堆逻辑是
largest最大节点下标
左节点下标 右节点下标
如果左节点比父亲节点大 就更新最大节点下标 右边同理
然后发现如果largest节点变了说明发生改动了 就应该交换 还需要进行递归操作 因为交换下来的节点也需要进行重复的判断
建堆完之后 头节点最大 需要交换头节点和最后一个节点 然后对头节点进行新一轮重复操作
桶排序:BucketSort
数据分组,各组之内进行排序
选择排序:SelectSort
找最大值放到最后/最小值放在最前面
6和3比3大 6和9比没九大 max=9的下标 9和1比 然后一顿比 最大放在最后
#include<stdio.h>
void SelectSort(int arr[],int length)
{
if(arr == NULL || length<=0)return;
int i;
int j;
int min;
for(int i=0;i<length-1;i++)
{
min=i;
for(int j=i+1;j<length;j++)
{
if(arr[j]<arr[min])
{
min=j;
}
}
//最小值放入最前面
if(min!= i)
{
arr[i]=arr[i]^arr[min];
arr[min]=arr[i]^arr[min];
arr[i]=arr[i]^arr[min];
}
}
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
SelectSort(arr,sizeof(arr)/sizeof(arr[0]));
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
插入排序:InsertSort
将待排序数据分成两部分,一部分有序,一部分无序,将无序元素依次插入到有序中去完成排序
#include<stdio.h>
void InsertSort(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i; //无序的第一个
int j; //有序的最后一个
int temp;
for(int i=1;i<length;i++)
{
j=i-1;
temp=arr[i]; //无序的第一个元素
while(j>=0 && temp<arr[j])
{
arr[j+1] = arr[j];
j--;
}
arr[j+1]=temp;
}
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
InsertSort(arr,sizeof(arr)/sizeof(arr[0]));
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
希尔排序:ShellSort
将数据分组,各组之内插入排序,比原有插入排序更快,适合大量数据,不常用。
不稳定
计数排序:CountingSort
核心思想:基于非比较的排序
1.找最大值和最小值
2.计数
3.排序
#include<stdio.h>
#include<stdlib.h>
#include<string.h> //memset
void CountingSort(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
int min = arr[0];
int max = arr[0];
//最大值最小值查找
for(int i=1;i<length;i++)
{
if(arr[i]<min)
{
min=arr[i];
}
if(arr[i]>max)
{
max=arr[i];
}
}
//计数空间
int *pCount=NULL;
pCount=(int*)malloc(sizeof(int)*(max-min+1));
memset(pCount,0,sizeof(int)*(max-min+1));
//计数
for(i=0;i<length;i++)
{
pCount[arr[i]-min]++;
}
//名次
for(int i=1;i<max-min+1;i++)
{
pCount[i]=pCount[i]+pCount[i-1];
}
//排序
int *pNew = (int*)malloc(sizeof(int)*length);
for(i=length-1;i>=0;i--)
{
pNew[pCount[arr[i]-min]-1]=arr[i];
pCount[arr[i]-min]--;
}
//放回原数组
for(int i=0;i<length;i++)
{
arr[i]=pNew[i];
}
free(pNew);
pNew=NULL;
free(pCount);
pCount=NULL;
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {2,4,7,1,5,14,89,13,2};
CountingSort(arr,sizeof(arr)/sizeof(arr[0]));
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
基数排序:RadixSort
LSD:低位优先
MSD:高位优先
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
int value;
struct node *pNext;
}Radix;
void RadixSort(int arr[],int length)
{
if(arr == NULL || length <= 0)return;
//找最大值
int nMax = arr[0];
int i;
for(int i=1;i<length;i++)
{
if(arr[i] > nMax)
{
nMax = arr[i];
}
}
//计算最大值位数
int nCount = 0;
while(nMax)
{
nMax/=10;
nCount++;
}
//按位处理
int nLoopTimes;
int nbase = 1;
//表头
Radix **pRadix = NULL;
pRadix = (Radix**)malloc(sizeof(Radix*)*10);
memset(pRadix,0,sizeof(Radix*)*10);
for(nLoopTimes = 1;nLoopTimes<=nCount;nLoopTimes++)
{
i = nLoopTimes;
while(i>1)
{
nbase*=10;
i--;
}
//数据入组
Radix *pTemp = NULL;
for(i = 0;i<length;i++)
{
pTemp = (Radix*)malloc(sizeof(Radix));
pTemp->value = arr[i];
pTemp->pNext = NULL;
//尾添加
if(pRadix[arr[i]/nbase%10] == NULL)
{
pRadix[arr[i]/nbase%10] = pTemp;
}
else
{
Radix *pNode = pRadix[arr[i]/nbase%10];
while(pNode->pNext)
{
pNode = pNode->pNext;
}
pNode->pNext = pTemp;
}
}
//放回
int j=0;
for(i=0;i<10;i++)
{
pTemp = pRadix[i];
while(pTemp)
{
arr[j]=pTemp->value;
pTemp = pTemp->pNext;
j++;
}
}
//释放
Radix *pDel = NULL;
for(int i=0;i<10;i++)
{
pTemp = pRadix[i];
while(pTemp)
{
pDel = pTemp;
pTemp = pTemp->pNext;
free(pDel);
pDel = NULL;
}
}
//清空
memset(pRadix,0,sizeof(Radix*)*10);
}
free(pRadix);
pRadix = NULL;
}
void Print(int arr[],int length)
{
if(arr == NULL || length <=0)return;
int i;
for(int i=0;i<length;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {53, 3, 542, 748, 14, 214, 154, 63, 616};
RadixSort(arr,sizeof(arr)/sizeof(arr[0]));
Print(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}