算法基础===》==》=》排序(内部排)

本文介绍了Java中一些基本的排序算法,包括插入排序(直接插入排序、希尔排序)、交换排序(冒泡排序、快速排序)、选择排序(直接选择排序、堆排序),给出了各算法的代码实现,并分析了它们的时间复杂度、稳定性等特性,强调要根据具体情况选择合适的排序算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自: https://blog.youkuaiyun.com/qq_43595030/article/details/91344579

 

版权声明: https://blog.youkuaiyun.com/qq_43595030/article/details/91344579
一些最基本的排序算法:

插入排序
交换排序
选择排序
@ 插入排序:

1-直接插入排序:

从前端插入
从后端插入
2-希尔(Shell)排序

1-直接插入排序:

从前端插入:
int arr[]={999,1,2,5,8,4,3,9,7};//"999"是一个容储器(arr[0]是一个监视哨),不参与排序。
void InsertSort(int n)
{
    int i,j;
    for(i=2;i<=n;i++)//进行n-1次排序
    {
        arr[0]=arr[i];//设置监视哨---减少扫描量,提高效率。
        j=i-1;//j代表有序序列的最后一个元素
        while(arr[0]<arr[j])
        {
            arr[j+1]=arr[j];//记录后移
            j--;
        }
            arr[j+1]=arr[0];//把存放在arr[0]中的原记录插入到正确位置
    }
}

从后端插入:
int arr[]={0,1,2,5,8,4,3,9,7,999};//"999"是一个容储器(arr[n+1]是一个监视哨),"0"是填补i=0的空白位置,"999"与"0"均不参与排序。
void InsertSort(int n)//从第n-1个元素开始向它前面插入,直到第一个元素插入为止。
{
    int i,j;
    for(i=n-1;i>=1;i--)//进行n-1次排序
    {
        arr[n+1]=arr[i];//设置监视哨
        j=i+1;//j代表有序序列的最后一个元素
        while(arr[n+1]>arr[j])
        {
            arr[j-1]=arr[j];//记录前移
            j++;
        }
            arr[j-1]=arr[n+1];//把存放在arr[n+1]中的原记录插入到正确位置
    }
}


2-希尔(Shell)排序==>直接插入排序的改进版

void InsertSort(int n)
{
    int i,j,d;
    for(d=n/2;d>=1;d=d/2)//进行n-1次排序
    {
        for(i=d+1;i<=n;i++)
        {
        arr[0]=arr[i];//设置监视哨
        j=i-d;//前后位置的增量为d,而不是1
        while(j>0&&arr[0]<arr[j])
        {
            arr[j+d]=arr[j];//记录后移,查找插入位置
            j=j-d;
        }
            arr[j+d]=arr[0];//插入
        }
    }
}

------》源代码:

#include<iostream>
using namespace std;

//1.数组的初始化:
int arr[]={999,1,2,5,8,4,3,9,7};//"999"是一个容储器(arr[0]是一个监视哨),不参与排序。

//2.希尔排序:
void InsertSort(int n)
{
    int i,j,d;
    for(d=n/2;d>=1;d=d/2)//进行n-1次排序
    {
        for(i=d+1;i<=n;i++)
        {
        arr[0]=arr[i];//设置监视哨
        j=i-d;//前后位置的增量为d,而不是1
        while(j>0&&arr[0]<arr[j])
        {
            arr[j+d]=arr[j];//记录后移,查找插入位置
            j=j-d;
        }
            arr[j+d]=arr[0];//插入
        }
    }
}

void Show_arr(int n)
{
    int i;
    for(i=1;i<=n;i++)
        cout<<arr[i]<<'\t';
    cout<<endl;
}

void main()
{
    InsertSort(8);
    Show_arr(8);
}


直接插入排序的算法的时间复杂度为O(n^2),直接插入排序是一种稳定的排序方法。而shell_sort的算法的时间复杂度为O(n* log2^n)~ O(n ^2) 大略为O(n^(3/2)),shell_sort不是一种稳定的排序方法

@交换排序:

冒泡排序
快速排序
1- 冒泡排序:

void Bubble_Sort(int *a,int n)
{
    int  i, j, t;
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-i-1;j++)
            if(a[j]>a[j+1])
            {
                t=a[j];
                a[j]=a[j+1];
                a[j+1]=t;
            }
    }
}

2-快速排序:

void Quick_Sort(int low,int high)
{
    if(low>=high)
        return ;
    int i=low,j=high;//避免引起歧义
    arr[0]=arr[low];
    while(i<j)
    {
        while(i<j&&arr[0]<=arr[j])//"i<j"绝对不能省,此处与外循环的含义不同
            j--;
        arr[i]=arr[j];
        while(i<j&&arr[i]<=arr[0])
            i++;
        arr[j]=arr[i];
    }
    arr[i]=arr[0];
    Quick_Sort(low,i-1);
    Quick_Sort(i+1,high);
}

------》源代码:

#include<iostream>
using namespace std;

//1.数组的初始化:
int arr[]={0,1,2,5,8,4,3,9,7};

//2.快速排序:一个形象的比喻-》“选取一个中间点,两边互相扔石头”
void Quick_Sort(int low,int high)
{
    if(low>=high)
        return ;
    int i=low,j=high;//避免引起歧义
    arr[0]=arr[low];
    while(i<j)
    {
        while(i<j&&arr[0]<=arr[j])//"i<j"绝对不能省,此处与外循环的含义不同
            j--;
        arr[i]=arr[j];
        while(i<j&&arr[i]<=arr[0])
            i++;
        arr[j]=arr[i];
    }
    arr[i]=arr[0];
    Quick_Sort(low,i-1);//这里采用递归来化简算法的难度
    Quick_Sort(i+1,high);
}
void Show_arr(int n)
{
    int i;
    for(i=1;i<=n;i++)
        cout<<arr[i]<<'\t';
    cout<<endl;
}

void main()
{
    Quick_Sort(1,8);
    Show_arr(8);
}

冒泡排序的算法的时间复杂度为O(n^2),是一种稳定的排序方法。
快速排序的算法的时间复杂度为O(n* log2^n)~ O(n ^2),不是一种稳定的排序方法。

@选择排序:

直接选择排序
堆排序
直接选择排序:

void Sort(int *a,int len)
{
    int i,j,min,t;
    for(i=0;i<len-1;i++)
    {
        for(min=i,j=i+1;j<len;j++)
            if(a[min]>a[j])
            {
                min=j;
            }
            if(min!=i)
            {
                t=a[i];
                a[i]=a[min];
                a[min]=t;
            }
    }
}

------》源代码:

#include<iostream>
using namespace std;

//1.数组的初始化:
int arr[]={1,2,5,8,4,3,9,7};

//2.选择排序:
void Sort(int *a,int len)
{
    int i,j,min,t;
    for(i=0;i<len-1;i++)
    {
        for(min=i,j=i+1;j<len;j++)
            if(a[min]>a[j])
            {
                min=j;
            }
            if(min!=i)
            {
                t=a[i];
                a[i]=a[min];
                a[min]=t;
            }
    }
}
void Show_arr(int n)
{
    int i;
    for(i=0;i<n;i++)
        cout<<arr[i]<<'\t';
    cout<<endl;
}

void main()
{
    Sort(arr,8);
    Show_arr(8);
}

堆排序:==>选择排序的改进版
*什么是堆?—
堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的数值或索引总是小于(或者大于)它的父节点。
堆排序的生成及其排序原理:

堆排序的实现:

void Adjust(int i,int n)//i代表待调整元素的下标,n代表最后一元素的下标。
{
    int j;
    arr[0]=arr[i];
    while(i<n&&2*i<=n)
    {
        j=2*i;//j为i左孩子下标
        if(j<n&&arr[j]>arr[j+1])
            j++;//j指向较小的孩子
        if(arr[0]>arr[j])
        {
            arr[i]=arr[j];
            i=j;
        }
        else
            break;
    }
    arr[i]=arr[0];
}
void Build_Heap(int n)
{
    int i;
    for(i=n/2;i>0;i--)
        Adjust(i,n);
}
void Show_arr(int n)
{
    int i;
    for(i=1;i<=n;i++)
        cout<<arr[i]<<'\t';
    cout<<endl;
}
void Heap_Sort(int n)
{
    int i,t;
    Build_Heap(n);
    cout<<"初始堆积树:"<<endl;
    Show_arr(8);
    cout<<endl;
    for(i=n;i>1;i--)
    {
        t=arr[1];
        arr[1]=arr[i];
        arr[i]=t;
        cout<<endl<<"第  "<<n-i+1<<"趟:"<<endl;
        Show_arr(8);
        Adjust(1,i-1);
    }
}

------》源代码:

#include<iostream>
using namespace std;

//1.数组的初始化:
int arr[]={0,1,2,5,8,4,3,9,7};

/*2.堆积树的调整过程:
从二叉树的叶子节点处往上逐一比较来建立最大堆积树:*/
void Adjust(int i,int n)//i代表待调整元素的下标,n代表最后一元素的下标。
{
    int j;
    arr[0]=arr[i];
    while(i<n&&2*i<=n)
    {
        j=2*i;//j为i左孩子下标
        if(j<n&&arr[j]>arr[j+1])
            j++;//j指向较小的孩子
        if(arr[0]>arr[j])
        {
            arr[i]=arr[j];
            i=j;
        }
        else
            break;
    }
    arr[i]=arr[0];
}

//3.堆积树的建立:
void Build_Heap(int n)
{
    int i;
    for(i=n/2;i>0;i--)
        Adjust(i,n);
}

//显示:
void Show_arr(int n)
{
    int i;
    for(i=1;i<=n;i++)
        cout<<arr[i]<<'\t';
    cout<<endl;
}

//4.堆积排序:
void Heap_Sort(int n)
{
    int i,t;
    Build_Heap(n);
    cout<<"初始堆积树:"<<endl;
    Show_arr(8);
    cout<<endl;
    for(i=n;i>1;i--)
    {
        t=arr[1];
        arr[1]=arr[i];
        arr[i]=t;
        cout<<endl<<"第  "<<n-i+1<<"趟:"<<endl;
        Show_arr(8);
        Adjust(1,i-1);
    }
}
void main()
{
    Show_arr(8);
    cout<<endl;
    Heap_Sort(8);
}

直接选择排序的算法的时间复杂度为O(n^2),由于直接选择排序交换次数少,当记录占用的字节数较多时,通常比直接插入排序的执行速度要快一些。但它却并不是一种稳定的排序方法,综合来看其性价比 较低.
堆排序方法对记录数较小的排序效果并不理想,但对于n较大的文件很有意义,因为其运行时间主要建立在初始建堆和反复调整堆上。
建堆的时间复杂度与堆所对应的完全二叉树的深度的数量级log2^n 有关,而调用数量级为n,所以整个堆排序的时间复杂度为O(n* log2^n)。在空间复杂度方面,堆排序只需要一个辅助空间,为O(1)。此外,堆排序并不是稳定的排序哦。

*ps:在算法的设计中排序的方法有很多种,但具体情况还需要具体分析,在情景中应当采取最合适的排序算法。
--------------------- 
作者:九霄云客 
来源:优快云 
原文:https://blog.youkuaiyun.com/qq_43595030/article/details/91344579 
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值