排序算法


快速排序

设置个关键字,将大的放在它后面,小的放在前面,分成两个子表,并且重复上述过程,直到每一个子表只有一个记录为止

const quickSort = function(arr){
  if(arr.length <= 0)return arr;
  const index = Math.floor(arr.length / 2);
  const key = arr.splice(index, 1)[0];
  const left = [];
  const right = [];
  for(let i = 0; i < arr.length; i++){
    if(arr[i] < key)left.push(arr[i]);
    else right.push(arr[i]);
  }
  return quickSort(left).concat([key], quickSort(right));
}
console.log(quickSort([2, 5, 1, 9, 6, 1, 4]));
console.log(['Jan', 'March', 'April', 'June'].splice(1, 1, 'Feb'));

1.不稳定排序

2.多用于顺序结构

3.时间复杂度O(nlog2 n)。 空间复杂度为O(log2 n), 最坏O(n).

最坏情况是逆序,或基本有序(顺序)

直接插入排序

这里采用的是从后向前的比较方式,(从前向后其实也可以)

有点像打牌,抽牌,然后选择地方放好

function insertion(array) {
  checkArray(array);
  for (let i = 1; i < array.length; i++) {
    for (let j = i - 1; j >= 0 && array[j] > array[j + 1]; j--)
      swap(array, j, j + 1);
  }
  return array;
}

1.稳定排序

2.适用于顺序表和链表

3.时间复杂度为O(n^2) 空间复杂度为O(1),只需要一个r[0]

优化插入排序

变量覆盖

const insertSort = (arr, start = 0, end) => {
  end = end || arr.length;
  for(let i = start; i < end; i++) {
    let e = arr[i];
    let j;
    for(j = i; j > start && arr[j - 1] > e; j --)
      arr[j] = arr[j-1];
    arr[j] = e;
  }
  return;
}

折半插入排序

其实就是直接插入排序引入了折半的思想

//算法8.2 折半插入排序
#include <iostream>
using namespace std;
#define  MAXSIZE  20                      //顺序表的最大长度
typedef struct
{
    int key;
    char *otherinfo;
}ElemType;
//顺序表的存储结构                         
typedef struct
{
    ElemType *r;                                     //存储空间的基地址
    int  length;                                    //顺序表长度
}SqList;                                            //顺序表

void BInsertSort(SqList &L){
    //对顺序表L做折半插入排序
    int i,j,low,high,m;
    for(i=2;i<=L.length;++i)
    {
        L.r[0]=L.r[i];                              //将待插入的记录暂存到监视哨中
        low=1; high=i-1;                            //置查找区间初值
        while(low<=high)
        {                                            //在r[low..high]中折半查找插入的位置
            m=(low+high)/2;                         //折半
            if(L.r[0].key<L.r[m].key)  high=m-1;    //插入点在前一子表
            else  low=m+1;                               //插入点在后一子表
        }//while
        for(j=i-1;j>=high+1;--j)  L.r[j+1]=L.r[j];    //记录后移
        L.r[high+1]=L.r[0];                            //将r[0]即原r[i],插入到正确位置
    }                                                //for
}                                                    //BInsertSort

void Create_Sq(SqList &L)
{
    int i,n;
    cout<<"请输入数据个数,不超过"<<MAXSIZE<<"个。"<<endl;
    cin>>n;                                            //输入个数
    cout<<"请输入待排序的数据:\n";
    while(n>MAXSIZE)
    {
        cout<<"个数超过上限,不能超过"<<MAXSIZE<<",请重新输入"<<endl;
        cin>>n;
    }
    for(i=1;i<=n;i++)
    {
        cin>>L.r[i].key;
        L.length++;
    }
}

void show(SqList L)
{
    int i;
    for(i=1;i<=L.length;i++)
        cout<<L.r[i].key<<endl;
}

void main()
{
    SqList L;
    L.r=new ElemType[MAXSIZE+1];
    L.length=0;
    Create_Sq(L);
    BInsertSort(L);
    cout<<"排序后的结果为:"<<endl;
    show(L);
}

1.稳定排序

2.仅适用于顺序表

3.时间复杂度为O(n^2),但是平均性能>直接插入。 空间复杂度为O(1),只需要一个r[0]

希尔排序

通过分组进行大浮动跳跃性排序,并且分组的形式是以设定的增量为基准

//算法8.3 希尔排序
#include 
using namespace std;
#define  MAXSIZE  20                      //顺序表的最大长度
typedef struct
{
    int key;
    char *otherinfo;
}ElemType;
//顺序表的存储结构                         
typedef struct
{
    ElemType *r;                                     //存储空间的基地址
    int  length;                                    //顺序表长度
}SqList;                                            //顺序表类型

void ShellInsert(SqList &L,int dk)
{
    //对顺序表L做一趟增量是dk的希尔插入排序
    int i,j;
    for(i=dk+1;i<=L.length;++i)
        if(L.r[i].key0&& L.r[0].key>n;                                        //输入个数
    cout<<"请输入待排序的数据:\n";
    while(n>MAXSIZE)
    {
        cout<<"个数超过上限,不能超过"<>n;
    }
    for(i=1;i<=n;i++)
    {
        cin>>L.r[i].key;
        L.length++;
    }
}

void show(SqList L)
{
    int i;
    for(i=1;i<=L.length;i++)
        cout<>t;
    for(i=0;i>dt[i];
    }
    ShellSort(L,dt,t);
    cout<<"排序后的结果为:"<

1.不稳定排序

2.仅适用于顺序表

3.时间复杂度取决于增量的决定,最少可以减少到n(log2 n)^2, n^3/2等。 空间复杂度为O(1),只需要一个r[0]

对于增量的选取很重要,希尔自带的增量设定为 {N/2, (N / 2)/2, …, 1} ,叫做希尔增量,常用但是效果并不拔群,其余的有 Hibbard:{1, 3, …, 2^k-1},Sedgewick:{1, 5, 19, 41, 109…} 等

字典排序

实现“ 1 2 3 , 1 3 2 , 2 1 3 , 2 3 1 , 3 1 2 , 3 2 1 ”的序列排序方法

代码实现如下

#include 
#define swap(a,b) {int temp=a;a=b;b=temp;} //交换a,b值
void sort(int arr[],int start,int end)//冒泡排序,从start到end的排序,使用时注意是数组的下标,如数组下标0-3排序,sort(arr,0,3)
{
    int i,j;
    for(i=0;i<=end-start;i++)
    {
        for(j=start;j<=end-i-1;j++)
        {
            if(arr[j]>arr[j+1])
                swap(arr[j],arr[j+1]);
        }
    }
}
void permutation(int arr[],int n) //字典排序
{
    int num=1,i=0,j=0,j1=0,k=0,a,b;
    for(i=1;i<=n;i++)//算出需要执行的次数,即全排列的次数,共n!种排法
    {
        num=num*i;
    }
    sort(arr,0,n-1);//先对数组进行一次按从小到大排列排序
    for(k=num;k>0;k--) //进行num次循环
    {
        for(i=0;i0;j--)
        {
            if(arr[j-1]=0;j1--)
        {
            if(arr[j1]>arr[a]) //这是字典排序第二步,获取arr[b]的值
            {
                b=j1;
                break;
            }
        }
        swap(arr[a],arr[b]); //这是第三步
        sort(arr,a+1,n-1); //这是第四步
    }
}
int main()
{
    int arr[]={1,2,4,3};
    permutation(arr,4);
    return 0;
}

总结得出字典排序算法四步法:

字典排序:
第一步:从右至左找第一个左邻小于右邻的数,记下位置i,值list[a]
第二部:从右边往左找第一个右边大于list[a]的第一个值,记下位置j,值list[b]
第三步:交换list[a]和list[b]的值
第四步:将i以后的元素重新按从小到大的顺序排列

举例:125643的下一个字典序列
第一步:右边值大于左边的3<4,4<6,6>5,则i=2,list[a]=5
第二步:从右往左找出第一个右边大于list[a]=5的值,找到6>5,j=3;list[b]=6;
第三步:交换list[a]和list[b]的值,序列125643->126543
第四步:将位置2以后的元素重新排序,126543->126345;
结束: 126345即125643的下一个序列

简单选择排序

选择关键字储存最小的记录:和表中的记录进行一一对比,选出最小记录放在开头,接着从第二个记录继续开始

//算法8.6 简单选择排序
#include <iostream>
using namespace std;
#define  MAXSIZE  20                                  //顺序表的最大长度
typedef struct
{
    int key;
    char *otherinfo;
}ElemType;
//顺序表的存储结构                         
typedef struct
{
    ElemType *r;                                     //存储空间的基地址
    int  length;                                    //顺序表长度
}SqList;                                            //顺序表类型

void SelectSort(SqList &L) 
{ 
   //对顺序表L做简单选择排序
    int i,j,k;
    ElemType t;
    for(i=1;i<L.length;++i) 
    {                                                  //在L.r[i..L.length] 中选择关键字最小的记录
        k=i;                 
        for(j=i+1;j<=L.length;++j)
            if(L.r[j].key<L.r[k].key)  k=j;            //k指向此趟排序中关键字最小的记录
        if(k!=i) {t=L.r[i];L.r[i]=L.r[k];L.r[k]=t;} //交换r[i]与r[k]        
     }                                                //for  
}                                                    // SelectSort

void Create_Sq(SqList &L)
{
    int i,n;
    cout<<"请输入数据个数,不超过"<<MAXSIZE<<"个。"<<endl;
    cin>>n;                                            //输入个数
    cout<<"请输入待排序的数据:\n";
    while(n>MAXSIZE)
    {
        cout<<"个数超过上限,不能超过"<<MAXSIZE<<",请重新输入"<<endl;
        cin>>n;
    }
    for(i=1;i<=n;i++)
    {
        cin>>L.r[i].key;
        L.length++;
    }
}

void show(SqList L)
{
    int i;
    for(i=1;i<=L.length;i++)
        cout<<L.r[i].key<<endl;
}

void main()
{
    SqList L;
    L.r=new ElemType[MAXSIZE+1];
    L.length=0;
    Create_Sq(L);
    SelectSort(L);
    cout<<"排序后的结果为:"<<endl;
    show(L);
}

1.稳定排序,但如果是采用“交换记录”,则会导致不稳定现象

2.顺序,链式皆可以使用

3.时间复杂度O( n^2 ),比直接插入快。 空间复杂度为O(l1).

基数排序

使用的大致思路是:根据关键字进行分类,再次排序,在分类,在排序,以此类推直至完成结果

如扑克牌中根据分13类,排序,再根据花色分类,再排序; 对百位数排序,先根据个位分类,排,再根据十位分类,排,再根据百位分类,排

//算法8.12 基数排序
#include 
using namespace std;
#include 
#include 
#include 
#define MAXNUM_KEY 8                    //关键字项数的最大值
#define RADIX 10                        //关键字基数,此时是十进制整数的基数
#define MAX_SPACE 10000
typedef char KeysType;                    //定义关键字类型为字符型
typedef int InfoType;                    //定义其它数据项的类型
typedef struct
{
    KeysType keys[MAXNUM_KEY];          //关键字
    InfoType otheritems;                   //其他数据项
    int next;
}SLCell;                                //静态链表的结点类型
typedef struct
{
    SLCell r[MAX_SPACE];                //静态链表的可利用空间,r[0]为头结点
    int keynum;                             //记录的当前关键字个数
    int recnum;                             //静态链表的当前长度
}SLList;                                //静态链表类型
typedef int ArrType[RADIX];                  //指针数组类型

void InitList(SLList *L)
{
    //初始化静态链表L(把数组D中的数据存于L中)
    char c[MAXNUM_KEY],c1[MAXNUM_KEY];
    int i,j,n,max;                        //max为关键字的最大值
    max=-10000;
    cout<<"请输入数据个数,不超过"<>n;
    while(n>MAX_SPACE)
    {
        cout<<"您输入的个数超过上限,请重新输入,不超过"<>n;
    }
    int *D=new int[n];
    cout<<"请输入"<>D[i];
        if(max=0;j--)
            cout<

1.稳定排序

2.适用于顺序表和链表,一般采用静态链式

3.时间复杂度为O(d(n+rd))/O(n) 空间复杂度为O(n+rd)

4.但是它的使用有严格要求,必须知道各级关键字的主次关系和各级关键字的取值范围

冒泡排序

将关键字大的记录“下沉”,与小的记录进行交换

//算法8.4 冒泡排序
#include 
using namespace std;
#define  MAXSIZE  20                      //顺序表的最大长度
typedef struct
{
    int key;
    char *otherinfo;
}ElemType;
//顺序表的存储结构                         
typedef struct
{
    ElemType *r;                                     //存储空间的基地址
    int  length;                                    //顺序表长度
}SqList;                                            //顺序表类型

void BubbleSort(SqList &L)
{
    //对顺序表L做冒泡排序
    int m,j,flag;
    ElemType t;
    m=L.length-1; flag=1;                 //flag用来标记某一趟排序是否发生交换
    while((m>0)&&(flag==1))
    {
        flag=0;                           //flag置为0,如果本趟排序没有发生交换,则不会执行下一趟排序
        for(j=1;j<=m;j++)
            if(L.r[j].key>L.r[j+1].key) 
            {
                flag=1;                    //flag置为1,表示本趟排序发生了交换
                t=L.r[j];L.r[j]=L.r[j+1];L.r[j+1]=t;    //交换前后两个记录
            }                            //if
        --m;
    }                                    //while
}                                        //BubbleSort

void Create_Sq(SqList &L)
{
    int i,n;
    cout<<"请输入数据个数,不超过"<>n;                                            //输入个数
    cout<<"请输入待排序的数据:\n";
    while(n>MAXSIZE)
    {
        cout<<"个数超过上限,不能超过"<>n;
    }
    for(i=1;i<=n;i++)
    {
        cin>>L.r[i].key;
        L.length++;
    }
}

void show(SqList L)
{
    int i;
    for(i=1;i<=L.length;i++)
        cout<

1.稳定排序

2.顺序链式都适用

3.时间复杂度O(n^2)。 空间复杂度为O(1).

归并排序

将相邻的两个记录(序列)排序,并成一个有序序列,并继续上述操作

//算法8.11 归并排序
#include 
using namespace std;
#define  MAXSIZE  20                                  //顺序表的最大长度
typedef struct
{
    int key;
    char *otherinfo;
}RedType;

typedef struct
{
    RedType *r;
    int length;
}SqList;

void Create_Sq(SqList &L)
{
    int i,n;
    cout<<"请输入数据个数,不超过"<>n;                                            //输入个数
    cout<<"请输入待排序的数据:\n";
    while(n>MAXSIZE)
    {
        cout<<"个数超过上限,不能超过"<>n;
    }
    for(i=1;i<=n;i++)
    {
        cin>>L.r[i].key;
        L.length++;
    }
}

//用算法8.10 相邻两个有序子序列的归并
void Merge(RedType R[],RedType T[],int low,int mid,int high)
{ 
   //将有序表R[low..mid]和R[mid+1..high]归并为有序表T[low..high] 
    int i,j,k;
    i=low; j=mid+1;k=low; 
    while(i<=mid&&j<=high)
    {                     
        //将R中记录由小到大地并入T中 
        if(R[i].key<=R[j].key) T[k++]=R[i++]; 
        else T[k++]=R[j++]; 
    } 
    while(i<=mid)                                    //将剩余的R[low..mid]复制到T中 
        T[k++]=R[i++];                 
    while(j<=high)                                   //将剩余的R[j.high]复制到T中 
        T[k++]=R[j++];                       
}//Merge 

void MSort(RedType R[],RedType T[],int low,int high)
{ 
    //R[low..high]归并排序后放入T[low..high]中 
    int mid;
    RedType *S=new RedType[MAXSIZE];
    if(low==high) T[low]=R[low];                    //序列长度为1,直接结束
    else
    { 
        mid=(low+high)/2;                           //将当前序列一分为二,求出分裂点mid 
        MSort(R,S,low,mid);                            //对子序列R[low..mid] 递归归并排序,结果放入S[low..mid] 
        MSort(R,S,mid+1,high);                        //对子序列R[mid+1..high] 递归归并排序,结果放入S[mid+1..high] 
        Merge(S,T,low,mid,high);                    //将S[low..mid]和S [mid+1..high]归并到T[low..high]  
    }//else 
}// MSort 

void MergeSort(SqList &L)
{ 
    //对顺序表L做归并排序 
    MSort(L.r,L.r,1,L.length); 
}//MergeSort 
void show(SqList L)
{
    int i;
    for(i=1;i<=L.length;i++)
        cout<

1.稳定排序

2.顺序,链式皆可以使用

3.时间复杂度O( nlog2 n ), 空间复杂度为O(n).


文章作者: Hello
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hello !
 上一篇
Serverless Serverless
ServerlessServerless(无服务计算)是指构建和运行不需要服务器管理的应用程序和概念 无服务器计算是一种按需提供后端服务的方法。无服务器提供程序允许用户编写和部署代码,而不必担心底层基础结构。从无服务器供应商处获得后端服务的
2021-10-24
下一篇 
牛客personal note 牛客personal note
小基础floor(x) 小于等于x的最大值整数(向下取整) ceil(x) 大于等于x的最小整数(向上取整)( #include<math.h> ) int 32位二进制 第一个是符号位正数为0,负数为1,后面是数值位 -
2021-09-16
  目录
Copyright © 2019 Hello | Powered by Hexo | Theme Matery
  站点总字数: 415.8k 字  总访问量:  次  总访问人数:  人