复习排序算法

1.直接插入排序

是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的,记录数增1的有序表。

void insertsort(int a[],int length){
    int i,j,shaobing;
    for(i=1;i<length;i++){
        if(a[i]<a[i-1]){//< 的话需要将a[i]插入有序子表
            shaobing=a[i];//复制为哨兵
            a[i]=a[i-1];
            for(j=i-2;j>=0&&shaobing<a[j];--j){
                a[j+1]=a[j];//记录后移
            }
        a[j+1]=shaobing;//插入到正确位置
        }
    }
}

2.冒泡排序

https://www.cnblogs.com/jhmu0613/p/6780741.html

冒泡排序是一种交换排序,通过两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

从第一个元素开始逐个地开始比较相邻的元素。每一次排序结尾总有一个最大的数被放在了最后。使用常数个辅助空间,所以空间复杂度为O(1).总的时间复杂度为O(n^2)。借助于“交换”进行排序的方法。一定要把冒泡的写法记清楚!!冒泡的实现细节可以有很多种变化的

void bubble_sort(int a[],int n){
for(int i=0;i<n;i++)
for(int j=0;j<n-i;j++){
    if(a[j]>a[j+1])
    swap(a[j],a[j+1]);//在逆序时交换相邻记录
}
}

重新贴一个修改的,时间复杂度为什么是O(n^2),从它的比较次数中也可看出,n-1+n-2+...+1=n(n-1)/2

#include <iostream>

using namespace std;

int main()
{
   int n;
   cin>>n;
   int k=0, a[n];
   while(k<n){
       cin>>a[k];
       ++k;
   }
   for(int i=0;i<n-1;++i){
       for(int j=0;j<n-i-1;++j){
           if(a[j]>a[j+1]){
               swap(a[j],a[j+1]);
           }
       }
   }
   for(int i=0;i<n;++i){
       cout<<a[i]<<" ";
   }
    return 0;
}

为什么最好的情况下的时间复杂度是O(n),因为仍然需要n-1次的比较。对于时间复杂度怎么计算来说,应该是这样:取决于比较次数和交换次数中较大的那个。

冒泡排序的优化 :

从整个过程中可以看出,即使到某一趟数据全部有序了,还是会继续接下来的i和j控制的循环,没有交换操作却依然有比较操作。增加一个flag

3.快速排序

是对起泡排序的一种改进。它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分全小于枢轴元素,另一部分全部大于枢轴元素。

是对冒泡排序的一种改进方法,在冒泡排序中,进行元素的比较和交换是在相邻元素之间进行的,元素每次交换只能移动一个位置,所以比较次数和移动次数较多,效率相对较低。而在快速排序中,元素的比较和交换是从两端向中间进行的,较大的元素一轮就能够交换到后面的位置,而较小的元素一轮就能交换到前面的位置,元素每次移动的距离较远,所以比较次数和移动次数较少,y速度较快,故称为“快速排序”。
快速排序的基本思想是:

  1. 在待排序的元素任取一个元素作为基准(通常选第一个元素,选择方法是从待排序元素中随机选取一个作为基准),称为基准元素;首先从high所指位置起向前搜索找到第一个关键字小于piotkey的记录和枢轴记录互相交换,然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录和枢轴记录互相交换,重复这两步纸质low=high为止。
  2. 将待排序的元素进行分区,比基准元素大的元素放在它的右边,比其小的放在它的左边;
  3. 对左右两个分区重复以上步骤直到所有元素都是有序的
int Partition(int a[],int low,int high){
    int pivotkey=a[low];
    while(low<high){
        while(low<high&&a[high]>=pivotkey){
            high--;
        }
        a[low]=a[high];
        while(low<high&&a[low]<=pivotkey){
            low++;
        }
        a[high]=a[low];
    }
    a[low]=pivotkey;
    return low;
}
void Qsort(int a[],int low,int high){
    if(low<high){
        int pivotloc=Partition(a,low,high);
        Qsort(a,low,pivotloc-1);
        Qsort(a,pivotloc+1,high);
    }
}
void QuickSort(int a[],int length){
    if(length<=0) return;
    Qsort(a,0,length-1);
}

 4.归并排序

归并排序又是一类不同的排序方法。归并的含义是将两个或两个以上的有序表组合成一个新的有序表。递归形式的2路归并算法在形式上较为简洁,但实用性很差。与快速排序和堆排序相比,归并排序的最大特点是它是一种稳定的排序方法。

5.简单选择排序

与冒泡排序不同,简单选择排序是等到合适的关键字出现才交换,每交换一次就可以达到一次冒泡的效果。我们只需要进行n-1趟排序即可。这个排序算法很好出选择题,时间复杂度,最好和最差都是一样的,因为其比较次数一样,第i趟排序都需要进行n-i次关键字的比较,基于最终的排序时间是比较和交换次数的综合,因此总的时间复杂丢仍然为O(n^2) 简单选择排序的性能上还是要略优于冒泡排序。

如果i选择的元素是最小的则不需要交换

void SelectSort(int a[],int n){
    if(n<=1) return;
    //利用一个中间元素temp来记录最小的数的位置
    for(int i=0;i<n-1;++i){
        int temp=i+1;
        for(int j=i+1;j<n;++j){
            if(a[j]<a[temp]){
                temp=j;
            }
        }
        if(a[temp]<a[i]){
            swap(a[temp],a[i]);
        }
    }
}

//教程中的解法
void selectsort(int a[],int n){
   int temp;
   for(int i=0;i<n-1;i++){
       temp=i;
       for(int j=i+1;j<n;j++){
          if(a[temp]>a[j){
             temp=j;
          }
       }
       swap(a[i],a[temp]);
   }
}

6.堆排序

堆排序是一种比较特殊的排序方式。堆是一种非线性的数据结构,可以把对看做一个数组,也可以看做一个完全二叉树。

按照堆的特点可以分为大顶堆和小顶堆。实现堆排序需要解决两个问题:如何由一个无序序列建成一个堆? 如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?

从无序序列建堆的过程其实就是一个反复“筛选”的过程。若将此序列看成是一个完全二叉树,则最后一个非终端节点是第n/2向下取整个元素。叶子节点都没有左右儿子了,做HeapAdjust也等于没有操作。

void HeapAdjust(int a[],int s,int m){
    //已知记录中的关键字出a[s]外均满足堆的定义,本函数调整a[s],使得a[s]到a[m]成为一个大顶堆。s是开始的位置
    int rc=a[s];
    //沿k较大的子节点向下筛选
    for(int j=2*s+1;j<=m;j=j*2+1){
        if(j<m&&(a[j]<a[j+1]))  ++j;  //j为key较大的记录的下标
        if(rc>=a[j]) break;   //rc应插入在位置s上,注意这一句:如果记录大于等于a[j]的话说明当前的位置是可以的,不需要挪了
        a[s]=a[j];
        s=j;
    }
    a[s]=rc;      //插入
}//HeapAdjust
void HeapSort(int a[],int n){
    for(int i=n/2-1;i>=0;--i)//把a[0]~a[n-1]建成大顶堆;主要思路:第一次保证0~0位置大根堆结构(废话),
        //第二次保证0~1位置大根堆结构,第三次保证0~2位置大根堆结构...直到保证0~n-1位置大根堆结构
       HeapAdjust(a,i,n-1);
    for(int i=n-1;i>=0;--i){
        swap(a[0],a[i]);
        HeapAdjust(a,0,i-1);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值