以下程序均与sort进行一百万数据对拍十次(有误请告知)
选择排序
#include <bits/stdc++.h>
using namespace std;
#define ll int
const int INF = INT_MAX;/// int的极限值
const int maxn = 1e5+7;
int mine = -INF; /// int 里面的最小值
int M[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",M+i);/// 输入
}
for (int i=1;i<=n;++i)
{
int t = mine;
int idx =-1;
for (int j=1;j<=n-i+1;++j)/// 从后往前找到大的元素放到后一个位置 (不包含已经排好序的)
/// (n-i+1)| 已经排好序.......
{
if (M[j] > t)
{
t = M[j];
idx = j;
}
}
///cout<<t<<' '<<idx<<endl;
swap(M[idx],M[n-i+1]);///交换第I大的值放到未排序的最后
}
for (int i=1;i<=n;++i)
{
printf("%d ",M[i]);
}
puts("");
return 0;
}
希尔排序
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int n;
int A[maxn];
void shell_sort()
{
/*
希尔排序 区别于之前的插入排序 希尔排序就是在原来的基础之上 首先按照一定的间隔进行插入排序
缩小间隔 然后使得数组相对有序 最后进行间隔为1 的插入排序 也就是最基础的插入排序
*/
for(int di = floor(n/2);di>=1;di = floor(di/2)) ///每次缩半 向上取整
{
for (int i=di+1;i<=n;++i)/// 间隔为di的插入排序
{
A[0] = A[i];
if (A[i] < A[i-di])
{
int j;
for (j=i-di;j>0&&A[0]<A[j];j-=di)
{
A[j+di] = A[j];
}
A[j+di] = A[0];
}
}
}
for (int i=1;i<=n;++i)
{
printf("%d ",A[i]);
}
puts("");
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)scanf("%d",A+i);
shell_sort();
return 0;
}
冒泡排序
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+4;
int M[maxn];
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d",M+i);
}
for (int i=1;i<=n-1;++i)
{
for (int j=1;j<=n-i;++j)
{
if (M[j]>M[j+1])
swap(M[j],M[j+1]);/// 其实冒泡排序的方法跟选择排序的很类似
/// 这里就是每次从n个中选出最大值 不就是两个两个比较选出最大值
/// 从n-1个数中选出次大值 然后这里的话就是把这个n-i+1个数里面的最大值往后移
/// 但是这样每次都需要交换(交换是需要时间的) 所以选择排序就将这里优化了
/// 直接找n-i+1里面的最大值 ,然后将他放在n-i+1的位置上交换一次就可以了
}
}
for (int i=1;i<=n;++i)
{
printf("%d ",M[i]);
}
puts("");
return 0;
}
快速排序
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int M[maxn];
int n;
/*
快速排序的思路就是找到一个中枢轴 然后将大于中枢轴的数往中枢轴后面放,否则放在他之前
然后遍历所有的轴ok (分治算法)
*/
void quick_sort(int ll,int rr)
{
if (ll>=rr) return ;
int l =ll;
int r =rr;
int t = M[ll];/// 直接以ll作为中枢轴,那么此时的l是空出来的
/// 此时的方法就是往两边丢数,最后产生的分界线放中枢轴
while (l<r)
{
while ((l<r) && M[r] >= t) --r;///先从右往左丢
if (l<r)
{
M[l] = M[r];
++l;
}
while ((l<r) && M[l] <= t) ++l;///从左往右丢
if (l<r)
{
M[r] = M[l];
--r;
}
}
M[l] = t;/// 最后一定是l>=r 假设最后是从右往左丢,那么r的数值丢到l,l++, l == r
/// 假设最后是从左往右丢 那么l的数值丢到r,--r l==r 所以这里l r都可以
quick_sort(ll,l-1);///继续丢他的左右子区间 直至区间长度为1 这样就每次将n长的区间做两半处理
quick_sort(l+1,rr);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d",M+i);
}
///cout<<1<<endl;
quick_sort(1,n);
for (int i=1;i<=n;++i)
{
printf("%d ",M[i]);
}
puts("");
return 0;
}
堆排序
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int M[maxn];
int n;
/*
堆排序的构造原理就是多棵二叉树的集合体 那么这棵二叉树满足 父亲节点大于(或者小于)所有的子根节点、
这样就保证根节点一定大于(或者小于)这棵子树的任何元素
然后这样构造的好处就是每次这棵树的总根就是最大(最小)值
但是他只满足于局部最优 ,局部最优从下往上就能够造成整体最大
*/
int update_heap_sort(int s,int sum)/// 当前根节点 需要更新的长度
{
int R = M[s];///最上面的那个根节点
for (int j=2*s;j<=sum;j*=2)///首先比较当前根所在的根和两个子节点 j记录子树的编号 s记录当前这棵子树的根
{
if ((j+1)<=sum && M[j]<M[j+1]) ++j;///记录j的位置 看看是否存在右子树 如果要往右子树方向交换就++
if (R > M[j]) break;///已经是最大的了就无须操作
else
{
M[s] = M[j];/// 先将大的数从子节点上升到根节点
s = j;/// 但是又要满足堆的条件 任意一个根节点都要大于两个子节点 所以要将刚刚交换的小数往下沉 继续更新
}
}
M[s] = R;///现在的s已经移动到合适的位置,可以将原来被交换的数放到s根上
}
void heap_sort()
{
for (int i=n/2;i>=1;--i)/// n/2代表就是最后一个节点n的根n/2
{
update_heap_sort(i,n);///对于所有的根节点 从下往上更新最大值
/// 保证当前任意的根节点的数大于子节点
}
for (int k=n;k>1;--k)
{
swap(M[1],M[k]);/// M[1] 表示他是最大值 因为M[1]在更新堆的时候就是最大值了
update_heap_sort(1,k-1);///最后的数值已经排好序了所以大根堆堆顶被移除就需要更新
}
}
void out()
{
for (int i=1;i<=n;++i)
{
printf("%d ",M[i]);
}
puts("");
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",M+i);
heap_sort();
out();
return 0;
}
插入排序(数组)
/*
插入排序
数组实现
将原来的数组划分为一个有序组和无序组 有序|无序 将无序数组的插入进有序数组就会使得无序变少有序增多
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5;///10^5
int a[maxn];
int main()
{
int n;
cin>>n;
for (int i=1;i<=n;++i)
{
cin>>a[i];
}
for (int i=2;i<=n;++i)///剩余的n-1个数组成的无序组
{
a[0] = a[i];///将所有待选择的数放在第一位进行比较,因为之后的数字移动会挤占当前位置
int j;
for (j=i-1;j>=1;--j)///从后往前边比对边移动 此时是在有序组中给无序组新来的数据找位置
{
if (a[0]>=a[j])break;
a[j+1] = a[j];
}
a[j+1] = a[0];///给i找到一个合适的位置进行插入
}
for (int i=1;i<=n;++i)
{
if (i!=n) printf("%d ",a[i]);
else printf("%d
",a[i]);
}
return 0;
}
插入排序(链表)
/*
插入排序链表实现
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
struct Node {
struct Node *next;
int idx;
};
int main()
{
int n;
scanf("%d",&n);
Node *Head;
Head = (struct Node*)malloc(sizeof(struct Node));/// 构建一个表头 ,储存一个空值
struct Node *p;
p = Head;
for (int i=1;i<=n;++i)
{
int x;
scanf("%d",&x);
struct Node *q;
q = (struct Node*)malloc(sizeof(struct Node));
q->idx = x;
p->next = q;///不断的将新的q插入到p之后
p = p->next;
}
p->next = NULL;/// 表尾为空
if (Head->next)///存在第一个数据才排序
{
struct Node *p;
p = Head->next->next;///记录下一个位置,防止被覆盖
Head->next->next = NULL;///链表截断 一个有序组,一个无序组
while (p)
{
struct Node *q = p->next;
struct Node *t = Head;
while (t->next&&p->idx>t->next->idx)t = t->next;///移动,从前往后依次比对
p->next = t->next;///比对完成,完成插入
t->next = p;
p = q;
}
}
for (struct Node *T=Head->next;T;T=T->next)
{
printf("%d ",T->idx);
}
return 0;
}
插入排序(静态链表)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int M[maxn];
int N[maxn];///变化之前的链数组
int W[maxn];///变化之后的链数组
int n;
/*
插入排序的主要思路就是一个有序组和一个无序组
A1 | A2 A3 A4 A5
然后的话将右边的无序区的数组一个一个的插入左边的有序组
*/
void init()
{
N[0] = 1;
///处理下边界,此处相当于表头节点
for (int i=1;i<=n;++i) N[i] = i+1;
///初始化 ,当前和下一个相连的下标就是当前下标+1
N[n] = 0;
///链表最后就指向0
}
/*
静态链表
M数据负责储存原始数据
N数组相当于指针,指出下一个
N[i]记录的是和i相连的下一个区块的下标
*/
void out(int x)
{
if (x)
{
printf("%d ",M[x]);
out(N[x]);
}
}/// 输出函数
int main()
{
scanf("%d",&n);
init();
for (int i=1;i<=n;++i)
{
scanf("%d",M+i);
/// cout<< M[i]<<endl;
}
if (N[0])
{
int p = 2;
N[1] = 0; ///类似于之前的链表,只不过相当于将next指针换成一个数组 首先将链表的头截断
while (p)
{
int t = 0;
int q = N[p];/// 记录下p的下一个坐标 防止丢失
while (N[t] && M[p]>M[N[t]]) t = N[t];/// 找到有序组中可以插入的位置 找到的就是可以插入的位置的(前面那个)
N[p] = N[t]; /// 首先取代t,将t的后面的那一段接给p
N[t] = p;/// t的下一个就是p
p = q;///无序组中的下一个
}
}
out(N[0]);///输出
cout<<endl;
return 0;
}
静态链表转有序数组
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int M[maxn];
int N[maxn];///变化之前的链数组
int W[maxn];///变化之后的链数组
int n;
/*
插入排序的主要思路就是一个有序组和一个无序组
A1 | A2 A3 A4 A5
然后的话将右边的无序区的数组一个一个的插入左边的有序组
*/
void init()
{
N[0] = 1;
///处理下边界,此处相当于表头节点
for (int i=1;i<=n;++i) N[i] = i+1;
///初始化 ,当前和下一个相连的下标就是当前下标+1
N[n] = 0;
///链表最后就指向0
}
/*
静态链表
M数据负责储存原始数据
N数组相当于指针,指出下一个
N[i]记录的是和i相连的下一个区块的下标
*/
void out(int x)
{
if (x)
{
printf("%d ",M[x]);
out(N[x]);
}
}/// 输出函数
int main()
{
scanf("%d",&n);
init();
for (int i=1;i<=n;++i)
{
scanf("%d",M+i);
/// cout<< M[i]<<endl;
}
if (N[0])
{
int p = 2;
N[1] = 0; ///类似于之前的链表,只不过相当于将next指针换成一个数组 首先将链表的头截断
while (p)
{
int t = 0;
int q = N[p];/// 记录下p的下一个坐标 防止丢失
while (N[t] && M[p]>M[N[t]]) t = N[t];/// 找到有序组中可以插入的位置 找到的就是可以插入的位置的(前面那个)
N[p] = N[t]; /// 首先取代t,将t的后面的那一段接给p
N[t] = p;/// t的下一个就是p
p = q;///无序组中的下一个
}
}
///out(N[0]);///输出
///cout<<endl;
/// 之前的已经按照静态链表的数组进行储存
/// 现在需要将数组变成有序数组 就不需要N数组的辅助
for (int k=0;k<=n;++k)
{
W[k] = N[k];/// 进行复制
}
int i = 1;
int j = N[0];
for (i = 1;i < n;++i)
{
///cout<<i<<' '<<j<<endl;
if (i==j) /// i是摆放的位置 j是摆放的数据来源的下标 相同就直接下一个
{
j = N[j];
}
else if(i<j) /// 如果当前的在后面 直接交换 已经摆好位置的i被后面的M[j]取代,
/// 那么下次如果有之前的寻找的话,此时将W【i】变为J代表该位置已经被移动到j位置
{
swap(M[i],M[j]);
W[j] = W[i];
W[i] = j;
j = N[j];
}
else
{
int t = j;/// j本身不能动,因为要从这里寻找下一个位置
while (i>t) t=W[t]; /// i>j 说明我现在需要交换的数据来源于之前的j,但是之前的位置按照w[t]一直寻找
swap(M[i],M[t]);/// 跳到 i<j 的位置 然后进行交换
W[i] = t;
j = N[j];/// 但是原本的位置还是需要保留 因为每次都是根据之前的原来的连接关系来求解的
}
}
for (int t=1;t<=n;++t)
{
printf("%d ",M[t]);
}
puts("");
return 0;
}
归并排序 递归实现
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+7;
int op[maxn];///实际数组
int M[maxn];/// 中转的数组
void merge_sort(int l,int mid,int r)
{
int i = l;
int j = mid+1;
int t = 0;/// 中转数组的下标
while (i <= mid && j<= r)
{
if (op[i]<=op[j])/// 如果当前小于直接就放到左边
{
M[t] = op[i];
++i;
++t;
}
else
{
M[t] = op[j];
++t;
++j;
}
}
while (i<=mid)
{
M[t] = op[i];
++t;++i;
}
while (j<=r)///剩余的放回
{
M[t] = op[j];
++j,++t;
}
int rear = 0;
int tmp = l;
while (tmp<=r)
{
op[tmp] = M[rear];/// 赋值回原来的数组
++rear;
++tmp;
}
}
void M_sort(int l,int r)
{
if (l<r)
{
int mid = (r-l)/2+l;
M_sort(l,mid);/// 左区间进行分解
M_sort(mid+1,r);///左右区间进行分解
merge_sort(l,mid,r);/// 最后将区间进行归并
/// 由于是首先先进行分解递归然后归并的所以就是
/// 首先分解为2 2^2 2^3开始归并
}
}
int main()
{
int n;
cin>>n;
for (int i=1;i<=n;++i)cin>>op[i];
M_sort(1,n);
for (int i=1;i<=n;++i)
cout<<op[i]<<' ';
return 0;
}