七大常用排序算法

交换函数swap

//C++实现
void swap(int &left, int &right)
{
    int temp = left;
    left = right;
    right=temp;
    
}
/*指针作为参数的交换函数
void swap1(int *left, int *right)
{
    int temp = *left;
    *left = *right;
    *right = temp;
}
*/

【冒泡排序】

//C++实现
void bubble_sort(vector<int> &nums)
{
    int size=nums.size();
    
    for(int i=0;i<size;i++)        
    {
        for(int j=1;j<size-i;j++)
        {
            if(nums[i]>nums[j])
                swap(nums[i],nums[j]);
        }
    }
}


【冒泡排序改进】:使用flag做标记,当已经排序好之后就不需要遍历了

//C++实现
void bubble_sort_better(vector<int> &nums)
{
    int size=nums.size();
    
    for(int i=0;i<size && flag;i++)        
    {
        int flag=0;
        for(int j=1;j<size-i;j++)
        {
            if(nums[i]>nums[j])
            {
                flag=1;
                swap(nums[i],nums[j]);
            }
        }
        if(!flag)        //如果flag一直保持0,表示并没有进行变换,表示后面的遍历都是增序,就需要再进行排序了
            break;
    }
}

【选择排序】

主要思想是:从0-size-1个元素中,逐个选做临时最小值【其实不一定是最小值】,然后再向后遍历,逐个比较,如果有元素比临时最小值要小的则保存其索引作为最小值的索引,直至遍历到数组末尾,此时将确认的最小值索引对应的值与临时最小值进行交换,依次类推,直至最后一个元素作为临时最小值,就完成排序过程
 

//C++实现
void choice_sort(vector<int> &nums)
{
    int min_index;        //记录当前循环最小值的索引
    int size=nums.size();
    for(int i=0;i<size;i++)
    {
        min_index=i;
        for(int j=i+1;j<size;j++)
        {
            if(nums[j]<nums[i])
                min_index=j;
        }
        swap(nums[i],nums[min_index]);
    }
}


【插入排序】

逐个遍历数组元素并与他前一个元素比较,直至发现当前元素的值比前一个元素的值小,保存当前值到temp,然后逐个比较他的前一个值,比temp
大的元素,则往后移动一个位置,直至找到小于temp的元素,则将temp插入其后,再继续往后遍历,知道最后一个元素
 

//C++实现
void insert_sort(vector<int> &nums)
{
    int size=nums.size();
    for(int i=1;i<size;i++)
    {
        if(nums[i]<nums[i-1])        //出现后面小于前面的情况,插入排序
        {
            int temp=nums[i];
            for(int j=i;nums[j-1]>temp && j>0;j--)    //将大于temp的都往后挪一位
                nums[j]=nums[j-1];
            nums[j]=temp;        //将temp插入到最后一个比他大的元素前面
        }
    }
}


【希尔排序】:通过从小到大逐渐减小increment的值,逐步将数组排成大致递增的,

/C++实现
void shell_sort(vector<int>  &nums)
{
    int size=nums.size();
    int increment;            //增量;可以理解成交换的步长
    for (increment = size / 2;increment > 0;increment /= 2)        //以2的倍数递减增量,当然增量还可以是其他方法确定,只要确保
                                                                //最后一次遍历的增量为1即可
    {
        for (i = increment;i < size;i++)
        {
            if(nums[i] < nums[increment])
                swap(nums[i],nums[increment]);
        }
    }
}

【归并排序】
采用分治的思想,先将整个数组按二分的方法逐步分解,最后分解成单个元素,然后再利用merge函数,将两个子数组合并到一个增序数组;依此类推,直至将整个数组排序成一个增序数组

//C++实现
//两个子数组合并函数:$1:子数组所在的数组 $2:第一个子数组的起点 $3:第一个子数组的终点 $4:第二个子数组的终点
void merge(vector<int> &nums , int first , int mid , int tail)
{
    vector<int> temp;
    int left=first;
    int right=mid+1;
    while(left <= mid && right <= tail)
    {
        if(nums[left] <= nums[right])
            temp.push_back(nums[left++]);
        else
            temp.push_back(nums[right++]);
    }
    
    while(left<=mid)
        temp.push_back(nums[left]);
    while(right<=tail)
        temp.push_back(nums[right]);
    
    int j=0;
    for(int i=first;i<=tail && j<temp.size();i++)
        nums[i]=temp[j++];
    
    
}

/*递归实现*/
void merge_sort(vector<int> &nums , int first , int tail)
{
    if(first == tail)    //递归停止条件
        return ;
    int mid=0;
    while(first<tail)
    {
        mid=(first+tail)/2;
        merge_sort(first,mid);
        merge_sort(mid+1,tail);
        merge(nums,first,mid,tail);
    }
}

/*非递归实现*/
//将待排序的数组按照顺序两两配对排序,然后在递增步长,以每四个元素进行配对排序,这样迭代下去就能将所有的子数组排序完
void merge_sort_diedai(vector<int> &nums)
{
    int size=nums.size();
    int first;        //记录子数组的第一个元素索引
    int tail;        //记录子数组的中间元素索引
    int mid;        //记录子数组的最后一个元素索引
    
    for (int i = 1; i < size; i *= 2)        //每次进行子数组合并的步长:1、2、4、8。。。
    {    
        first = 0;                            
        while (first + i < size)              //最后一个子数组存在(需要归并)
        {
            mid = first + i - 1;
            tail = mid + i < size ? mid + i : size - 1;//最后一个子数组可能不够大,此时就需要跟size来确定tail的值
            Merge(nums, first, mid, tail);
            first = tail + 1;               
        }
    }
}

【堆排序】:堆是一个完全二叉树。大顶堆:其每个节点的值都大于左右子节点的值 小顶堆:每个节点的值都小于等于其左右子节点的值

以下是我对于堆排序的一些理解,作图比较直观,容易理解

//C++实现
void Heapify(vector<int> &nums, int i, int size)  // 从A[i]向下进行堆调整
{
    //当前节点为非叶结点,则在完全二叉树里面,他的左右子节点的索引分别为2*i+1和2*i+2;
    
    int left_child = 2 * i + 1;         //左孩子索引
    int right_child = 2 * i + 2;        //右孩子索引
    int max_index = i;                        //选出当前结点与其左右孩子三者之中的最大值的索引,初始化为当前节点的索引
    if (left_child < size && nums[left_child] > nums[max_index])
        max_index = left_child;
    if (right_child < size && nums[right_child] > nums[max_index])
        max_index = right_child;
    if (max_index != i)            //当三个节点中,最大值不是当前节点,要将当前节点的值与最大值所在的节点进行交换
        swap(nums,i,max_index);                // 把当前结点和它的最大(直接)子节点进行交换
}

void heap_sort(vector<int> &nums)
{
    int heap_size=nums.size();
    
    // 建立一个大顶堆
    //在一个完全二叉树中,他的非叶结点为其前面(size/2-1)个节点,往后的都是叶结点
    for (int i = heap_size / 2 - 1; i >= 0; i--) //从每一个非叶结点开始向下进行堆调整
        Heapify(nums, i, heap_size);                       
        
    while (heap_size > 1)           // 堆(无序区)元素个数大于1,未完成排序
    {
        // 将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素
        // 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
        Swap(nums,0,--heap_size);        //将最后一个元素和第一个元素互换,并且heap_size--,去掉最后一个元素再接着循环
        
        for (int i = heap_size / 2 - 1; i >= 0; i--) 
            Heapify(nums, i, heap_size);        //互换后重新构建大顶堆,时间复杂度O(logn)
    }
    
}

【快速排序】

//C++实现
//分区处理,将待排序数组按照基准值分成左右子数组,保证左子数组全部小于右子数组,并且找出基准值对应的分界索引值
int partition(vector<int> &nums,int first,int tail)
{
    int left=first;
    int right=tail;
    int temp = nums[left];    //留作基准值
    
    while(left < right)        //直到left=right,此时基准值左边全部小于右边
    {
        while(left < right && nums[right] >= temp)    //从右往左遍历,直到遇到小于基准值的元素为止,保证right右边全是大于基准值的
            right--;
        swap(nums,left,right);                        //交换一次,基准值被交换到nums[right]
        while(left < right && nums[left] <= temp)    //从left开始遍历,直到找到大于基准值的元素,保证left左边全部小于基准值
            left++;
        swap(nums,left,right);                        //再交换一次,此时基准值被交换回nums[left]
    }
    return left;
}
//递归函数
void quick_sort(vector<int> &nums,int low,int high)
{
    int pivot;
    if(low < high)
    {
        pivot = partition(nums,low,high);    //将待排序数组分成基准值左右两个子数组
        
        quick_sort(nums,low,pivot-1);        //递归进行,将基准值左子数组进行分区处理
        quick_sort(pivot+1,high);            //递归进行,将基准值右子数组进行分区处理
    }    
    else    //递归终止条件
        return ;
}
main()
{
    quick_sort(nums,0,nums.size()-1);
}

这两篇博客我觉得都写得挺不错的,其中也有参考他们的算法,有兴趣的可以仔细地看一下

https://www.cnblogs.com/wangyingli/category/889107.html

https://www.cnblogs.com/eniac12/p/5329396.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值