排序算法(内排序)

目录

一、插入排序

二、希尔排序

三、堆排序

四、 选择排序

五、冒泡排序

六、快速排序

七、归并排序

1、递归版


概述:

                                       插入排序  ——后一位与前边进行比较

                  插入排序:   希尔排序  ——将数据划分为几个数据在进行直接排序

比较排序                        堆排序     —— 大顶堆排序(自适应建堆,重新自适应排序)

                  选择排序:   选择排序  ——从数组中选出最小的进行排序,放在左边进行排序

                                      冒泡排序  ——将最大的放在最后,依次循环

                  交换排序:    快速排序  ——分治法,选一个基准,左子序列放小于基准数,右子序列

                                       放大于基准数

                  归并排序:    先将数组划分为两个数组,对两个数组进行比较,较小的放在新的数组

                                     中,依次进行

一、插入排序

算法(升序):

1、取第二位与第一位进行比较,若第二位小于第一位,则替换第一位与第二位,  否则不变;

2、依次向后进行移动进行比较替换。

代码:    

void InsertSort(int* arr, int a)
{
    for(int i =0;i<n;i++)
    {
        int end =i;
        int temp = arr[end+1];
        while(end>=0)
        {
            if(arr[end]>temp)
            {
                arr[end+1] = arr[end];
                end--;
            }
            else
            {
                break
            }
        }
        arr[end+1]=temp;
    }
}

特性总结:

1、时间复杂度:O(N^2)

二、希尔排序

算法:                                                                                                                                              1、对数组进行划分,根据gap进行划分,当前数字与gap位之后的数据进行比较,若当前数据大于

gap数之后的数,将其进行调换,如果没有,跳出循环,依次进行;

2、同时gap也在不断发生变化,最后gap==1,进行最后的比较。

void ShellSort(int* arr, int n)
{
    int gap =n;
    while(gap>1)
    {
        gap = gap/2;
        for(int i =0;i<n-gap;i++)
        {
            int end =i;
            int temp = arr[end+gap];
            while(end>=0)
            {
                if(arr[end]>temp)
                {
                    arr[end+temp]=arr[end];
                    end -= gap;
                }
                else
                {
                    break;
                }
            }
            arr[end+gap] = temp;
        }
    }
}

希尔 排序的特性:

1、插入排序的优化; 

 2、时间复杂度,因为gap的取值,希尔排序的时间复杂度不固定。

三、堆排序

基本概念:

堆:近似完全二叉树的结构,采用数列储存。   

大顶堆:每个节点的值都大于或等于它的左右子节点的值。                                                         

小顶堆:每个节点的值都小于或者等于它的左右子节点的值。

性质:

1、用数组arr储存堆结构,对于下标为 i 的节点,他的左子节点为 2x i+1,右子节点为 2 x i+2,

父节点为( i - 1)/2;

2、最后一个非叶子节点的下标为arr.length / 2;

堆排序基本步骤:

 1、将初始堆构建为大顶堆(小顶堆),此堆为初始的无序区;

 2、将堆顶元素与最后一个元素交换,得到新的无序区arr[0,1,2,n-1]和有序区arr[n];

 3、调整新的无序堆区,因此对当前无序的堆区调整为新堆,后再次将arr[0]与无序区最后一个元

素交换,得到新的无序区arr[0…n-2]和新的有序区arr[n-1,n]。不断重复此过程直到有序区的元素个

数为n-1,则整个排序过程完成。

由一个无序序列建堆:

方法一:向堆中添加元素建堆

void addHeap(vector<int>& arr, int a)
{
    arr.push_back(a);
    int len = arr.length();
    if(len ==1);
    return ;
    int index = len-1;
    for(int i =(len-1)/2;i>=0;i--)
    {
        if(arr[i]>=a)
            break;
        if(arr[i]<a)
        {
            arr[index] = arr[i];
            index =i;
        }
        if(i==0)
            brek;
    }
    arr[index] = a;

}

方法二:自下而上的调整来建堆(eg:大顶堆)

/*
至上而下调整arr[s]的数据,使arr[s,...m]也成为一个大顶堆。
*/
void heapAgjust(vector<int>& arr, int s,int m)
{
    int temp =arr[s];//当前的根节点
    for(int i =2*s+1;i<=m;i=i*2+1)
    {
        //左右子树根之间比较
        if(i<m&&arr[i]<arr[i+1])//
            i++;//i指向较大数据节点的位置
        if(temp>=arr[i])
            break;
        arr[s]=arr[i];
        s =i;
    }
    arr[s] = temp;
}

堆排序

void swap(int a0, int a1)
{
    int tmp =a0;
    a1 =a0;
    a0 = tmp;
}

void HeapSort(vector<int>& arr)
{
    //1、处理边界值
    int len = arr.size();
    if (len<2)
        return;
    //根据调整创建一个大顶堆
    for(int i = (len-1)/2;i>=0;i--)
    {
        HeapAdjust(arr,i,len-1);
    }
    //不断缩小无序区
    for(int i =len-1;i>=1;i--)
    {
        //交换第一个与最后一个元素的,使序列arr[0,...len-2]c成为无序区
        swap(arr[0],arr[i]);
        //将arr[0,...,len-2]重新调整为大顶堆
        HeapAdjust(arr,0,i-1);
}

四、 选择排序

算法原理:1、第一次从待排序的数据中选出最小的一个元素,放在起始端,

                  2、然后选出次小的,放在最小元素的下一个位置,依次类推,直到最后一个元素结 

                       束。

void SelectSort(int* arr,int n)
{
    int begin =0;
    int end =n-1;
    while(begin<end)
    {
        int maxid = begin;
        int minid =end;
        for(int i = begin,i<=end;i++)
        {
            if(arr[i]<arr[minid])
                minid =i;
            if(arr[i>arr[maxid]])
                maxid =i;
         }
        swap(arr[begin],arr[minid]);
        //当最大值在begin时,通过上一步的交换后,最大值的下标为minid
        if(begin==maxid)
            maxid =minid;
        //最大值放在序列结尾
        swap(arr[maxid],arr[end]);
        begin++;
        end--;
    }
}

选择排序的算法特点:

1、时间复杂度:O(N^2)

2、空间复杂度:O(1)

3、不稳定,而且效率不高,实际中很少使用

五、冒泡排序

算法原理:(升序)

1、从左到右进行依次比较,若左边大于右边则交换,一直到找到最大的元素,交换到最后;

2、继续从左到右进行比较交换,找到第二最大元素,放在最大元素的前一个位置,依次直到最后。

void BubbleSort(int* arr, int n)
{
    for(int i =0;i<n;i++)
    {
        for(int j =1;j<n-i;j++)
        {
            if(arr[j-1]>arr[j])
                swap(&arr[j-1],&arr[j])

        }
    }
}

void swap(int* a,int *b)
{
    int tmp =*a;
    *a = *b;
    *b = tmp;
}

冒泡排序的特新总结:

1、时间复杂度:O(N^2)

2、空间复杂度:O(1)

3、不稳定

六、快速排序

分治算法:将问题分解为若干个规模较小、相互独立,且与原问题形式相同的子问题,快速排序是

                  分治算法的一种。

算法原理:将要排序的数据分割为分独立的两部分,其中一部分的数据比另一部分的数据都小;

                  然后继续对这两部分数据进行快速排序,整个过程可以递归进行,以此使得所有序列变

                  为有序序列。

步骤:从数列取出一个元素作为基准元素,以基准元素为标准,将问题分解为两个子序列,左子序

列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过

程,直到所有元素都排列在相应位置上为止。

1、递归版本

//Hoare版本
//left  --  数组的起始位置
//right -- 数组的终点位置(数组长度-1)
int QuickSort(int* arr,int left,int right)
{
     if(left>=right)
        return;
    int begin = left;
    int end = right;
    int keyi = left
    while(left<right)
    {
        //右边先走,找小
        while(left<right&&arr[right]>=arr[keyi])
        {
            right--;
        }
        //左边再走,找大
        while(left<right && arr[left]<= arr[keyi])
        {
            left++;
        }
        Swap(&arr[left], &arr[right]);
    }
    Swap(&arr[left], &arr[keyi])
    keyi =left;
    QuickSort(arr,begin,keyi-1);
    QuickSort(arr,keyi+1,end);
    
}

该方法有个特点,当key在最左边,且数组为有序,排序时需要新的栈帧,时间复杂度为n*logn,因此我们可以将key的位置进行随机排放。

七、归并排序

1、递归版

void _MergeSort(int* arr,int* tmp,int left,int right)
{
    if(left>=right)
        return;
    int mid =(right+left)/2;
    _MergeSort(arr,tmp,0,mid);
    _MergeSort(arr,tmp,mid+1,right);
    int left1 =left;
    int right1 = mid;
    int left2 = mid+1;
    int right2 = right;
    int k =0;
    while(left1<right1&&left2<right2)
    {
        if(arr[left1]<arr[left2])
        {
            tmp[k++]=arr[left1++];
        }
        else
        {
            tmp[k++]=arr[left2++];
        }
    }
    while(left1<right1)
    {
        tmp[k++]=arr[left1++];
    }
    while(left2<right2)
    {
        tem[k++] = arr[left2++];
    }
    memcpy(a+left,tmp+left,sizeof(int)*(right-left+1));
}



void megesort(int* arr,int int n)
{
    int* tmp = new int[n];
    if(tmp==NULL)
    {
        printf("内存申请失败");
        return;
    }
    _MergeSort(arr,tmp,0,n-1);
    delete[] tmp;
}




【数据结构】八大排序算法_x一季花开成海x的博客-CSDN博客

                       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值