插入排序 O(n1~2)
插入排序,之前张老师讲过,今天重新进行一个整理
插入排序的思想就是每次取出一个数然后从有序序列的最后一个开始比较,(其具体情况就看是升序还是降序,这里用升序来举例子)如果最后一个元素大于这个新的元素,说明这个新的元素不能放在这里,应该往前循环比较,直至碰见比自己小了,那说明后面比自己大,前面的自己小,就将这个新数插进去
还有一点需要声明就是说,我们得将一个基准数比较,意思就是说第一个数不需要排序,我们后面的数根据它来比较,即最后一个元素
...//输入处理
for(int i=1;i<n;i++)
{
j=i;//复制
temp=a[j+1];//获取新的元素,基准数
while(temp>a[j]&&j>=1)//循环比较然后防止边界
{
a[j+1]=a[j];//往后移一位
j--;
}
a[j+1]=a[j];//插到这里,因为会多减1,所以这里多加1
}
...//输出处理
选择排序 O(n2)
选择排序是我最喜欢的一种排序,好想,好实现,简单便捷
这个排序的思想非常的简单,就是说每次都在序列中取一个最小值放在序列里面,然后这个新的序列就是一个升序的了(如果降序排列就取最大值)
废话不多说
...//输入处理
for(int i=1;i<=n;i++)
{
int minn=i;
for(int j=i+1;j<=n;j++)//往后找,因为前面有序
{
if(a[j]<a[minn])
minn=j;
}
int temp;
temp=a[i];
a[i]=a[minn];
a[minn]=temp;
}
...//输出处理
桶排序 O(n+m)
啊啊啊啊啊啊啊啊啊啊啊啊
这个排序,我是真的很…因为当年(2020.11.7.CSP-j)我没有想到…
这个排序的时间非常的快,但是空间复杂度就太大了
这种排序的思想就是将序列全部扫一遍,然后把这个元素存到桶里面,最后依次输出桶的编号就好了
...//输入处理
for(int i=20000;i>0;i--)//枚举数据范围
{
while(book[i])
{
cout<<i;
book[i]--;
}
}
...//输出处理
冒泡排序 O(N2)
冒泡排序是一种比较高尚的算法,比较难理解,比较难想,有可能我到现在都还没弄明白
这种算法很稳定
通过交换两个数的值最后得出来一个有序序列,依次比较,大的在前小的在后,就像冒泡泡一样一直往上拱拱拱,这种排序算法比较慢,还很难实现,所以不介意使用
...//输入处理
for(int i=0;i<n;i++)//待排序的个数
{
for(int j=0;j<n-i;j++)//每次排序的轮数
{
if(a[i]>a[i+1])
{
swap(a[i],a[i+1]);
}
}
}
...//输出处理
快速排序 O(nlogn)
这个排序的思路很好理解,代码自我感觉不好实现
这个算法的过程如下:
1.在序列里面选择一个基准数,通常为数组第一个
2.将数组中小于基准数的数移动到左边,大于基准数的数移动到右边
3.对于左右两区间,递归重复实现2
其实我们看出来,这个排序的思想就是分治
void qs(int l,int r)
{
if(l<r)
{
int temp=a[l];//确定基准数
int i=l,j=r;
while(i<j)
{
while(i<j&&a[j]>temp)
j--;
while(i<j&&a[i]<=temp)
i++;//循环找与基准数相比的数
if(i<j)//大于基准数的小于等于基准数的交换
{
int t;
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
}
a[l]=a[i];
a[i]=temp;//基准数归位
//i、j相遇的位置就是基准数的位置
qs(l,i-1);
qs(i,r);//二分递归
}
基数排序 O(nklog n)
基数排序,是利用了桶排序,对与每一个数的每一位开始比较,利用桶,那么最后得到的结果就是一个有序的解了
329 457 329 329
457 657 839 457
657 329 457 657
839 839 657 839
所以最后的结果就是 329 457 657 839
void counting_sort(int p)
{
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; ++i) ++cnt[a[i].key[p]];//统计
for (int i = 1; i <= w[p]; ++i) cnt[i] += cnt[i - 1];//这里其实就是对优先级进行一个排序
// 为保证排序的稳定性,此处循环i应从n到1
for (int i = n; i >= 1; --i) b[cnt[a[i].key[p]]--] = a[i];
memcpy(a, b, sizeof(a));
}
归并排序 O(n log n)
个人理解的对并排序和快速排序一样,都是使用的分治这种思想进行排序
首先一个序列,我们要分成两半,然后对这两半逐位进行比较,将小的放进一个新的序列里面,这样这个序列就有序了
while(i<=mid&&j<=right)
{
if(a[i]<=a[j])
{
b[k]=a[i];
i++;
k++;
}//两组元素取最小的加入序列b
else
{
b[k]=a[j];
j++;
k++;
}
}
那么还得考虑两个情况,就是第一部分全部大于第二部分,也就是说在比较的时候就只进了一部分,另一部分一点都没动,所以还得开两个循环特殊处理
while(i<=mid)
{
b[k]=a[i];
i++,k++;
}//特殊处理两个序列,只执行一个
while(j<=right)
{
b[k]=a[j];
j++,k++;
}
然后就是全部代码
void ms(int left,int right)
{
if(left==right) return ;
int mid=(left+right)/2;//二分
ms(left,mid);
ms(mid+1,right);//二分递归
int i=left,j=mid+1,k=left;
while(i<=mid&&j<=right)//两组元素取最小的加入序列b
{
if(a[i]<=a[j])
{
b[k]=a[i];
i++;
k++;
}
else
{
b[k]=a[j];
j++;
k++;
}
}
while(i<=mid)//特殊处理
{
b[k]=a[i];
i++,k++;
}
while(j<=right)
{
b[k]=a[j];
j++,k++;
}
for(i=left;i<=right;i++)
{
a[i]=b[i];//复制
}
}
树形选择排序
这种算法又叫做锦标赛算法,这种算法就是利用将一共的,两个人分成若干组,然后两两比较,胜出的人数就会比原来少一半,然后接着执行直至得出一个冠军
这个图片就是这个的过程
个人理解怎么感觉和拓扑这么像,其实理解了过程代码就很好理解了