数据结构与算法6-排序算法

数据结构与算法-排序算法

往期内容
1-链表
2-栈与队列
3-树与图
4-哈希表
5-查找
6-排序
7-贪心
8-递归与分治
9-动态规划



常见的排序算法

在这里插入图片描述
不稳定的算法:快速排序,希尔排序,选择排序,堆排序


1.冒泡排序

1.1 低配版本的冒泡排序(交换)

void BubbleSort(int *arr,int length)
{
	for(int i=0;i<length;i++)
	{
		for(int j=i+1;j<length;j++)
		{
			if(arr[i]>arr[j])
			{
				int temp=arr[j];
				arr[j]=arr[i];
				arr[i]=temp;
			}
		}
	}
}

1.2 冒泡排序

  • 注意:第二个for循环j=length-i-1;一定要注意还有一个-1,因为对于n个数据其实只要比较n-1次,故需要-1
void BubbleSort1(int arr[],int length)
{
    for(int i=0;i<length;i++)
    {
        for(int j=0;j<length-i-1;j++)
        {
            if(arr[j]>arr[j+1])
            {
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
}

1.3 冒泡排序优化1

  • 设置一个标志位flag,但某一次没有发生交换则表示排序已经完成
void BubbleSort2(int arr[],int length)
{
    bool flag=true;//是否需要继续排序,只要有交换继续排序

    for(int i=0;i<length && flag;i++)
    {
        flag=false;
        for(int j=0;j<length-1-i;j++)
        {
            if(arr[j]>arr[j+1])
            {
                flag=true;
                
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
}

1.4 冒泡排序优化2-鸡尾酒排序

  • 也叫双向冒泡
    鸡尾酒排序:从低到高后从高到低
    冒泡排序:从低到高
//4.鸡尾酒排序:从低到高后又从高到低
void BubbleSort3(int arr[],int length)
{
    int i,temp;
    int left,right;
    left=0;
    right=length-1;

    while(left<right)
    {
        //从后往前
        for(i=right;i>left;i--)
        {
            if(arr[i-1]>arr[i])
            {
                temp=arr[i];
                arr[i]=arr[i-1];
                arr[i-1]=temp;
            }
        }
        left++;

        //从前往后
        for(i=left;i<right;i++)
        {
            if(arr[i]>arr[i+1])
            {
                temp=arr[i];
                arr[i+1]=arr[i];
                arr[i]=temp;
            }
        }
        right--;
    }

}

2.选择排序

每次只找对应的位置,第二层循环的时候 交换数据

void SelectSort(int *arr,int length)
{
    int idcard;//实质是先找到位置,在交换

    for(int i=0;i<length;i++)
    {
        idcard=i;
        for(int j=i+1;j<length;j++)
        {
            if(arr[idcard]>arr[j])
                idcard=j;
        }

        if(idcard!=i)
        {
            int temp=arr[idcard];
            arr[idcard]=arr[i];
            arr[i]=temp;
        }
    }
}

-类比 普通的交换排序,节省了 每次交换

void SelectSort0(int arr[],int length)
{
	for(int i=0;i<length;i++)
	{
		for(int j=i+1;j<length;j++)
		{
			if(arr[i]>arr[j])
			{
				int temp=arr[j];
				arr[j]=arr[i];
				arr[i]=temp;
			}
		}
	}
}

3.插入排序

对于任意的低i个位置,认为前i-1个位置是有序的,将当第i个位置的小于前面的元素,依次比较,并依次移动位置,知道空出的位置为0或者,满足条件为止。切记 要用临时变量保存插入元素的值。

void InsertSort(int *arr,int length)
{
    int target;

    for(int i=1;i<length;i++)
    {
        target=arr[i];

        int pos=i;//应该插入的位置
        while(pos>0 && target<arr[pos-1])
        {
            arr[pos]=arr[pos-1];
            pos--;
        }

        arr[pos]=target;
    }
}
  • 改进 二分插入排序
//7. 二分插入排序
void InsertSort1(int arr[],int length)
{
    for(int i=1;i<length;i++)
    {
        if(arr[i]<arr[i-1])
        {
            int target=arr[i];
            int left=0;
            int right=i-1;
            while(left<=right)
            {
                int mid=left+(right-left)/2;
                if(target>arr[mid])
                {
                    left=mid+1;
                }
                else
                {
                    right=mid-1;
                }

            }

            for(int j=i;j>left;j--)
            {
                arr[j]=arr[j-1];
            }
            arr[left]=target;
        }
    }
}

4.希尔排序

希尔排序实在插入排序的基础上进行变化的,希尔排序首先对数据进行分组,即每间隔gas的数据进行排序,然后依次改变gas的大小,最后一次一定要取到gas=1,最后一次得到完成的插入排序。
希尔排序参考视频

//8.希尔排序
void shellSort(int *arr,int length)
{
    int gas=length;//每次插入的间隔
    int target;//临时存续插入排序待排数据

    while(gas>0)
    {
        //插入排序部分
        for(int i=gas;i<length;i++)
        {
            target=arr[i];
            int pos=i;
            while(pos>0&& target<arr[pos-gas])//后移动数据
            //while(pos>=gas&& target<arr[pos-gas])//后移动数据
            {
                arr[pos]=arr[pos-gas];
                pos-=gas;
            }
            arr[pos]=target;

        }
        gas=gas/2;//改变间隔,在进行插入排序,一定要取到1
                  //进行完整的插入排序
    }
}
  • 对比插入排序与希尔排序
void InsertSort(int *arr,int length)
{
    //int gas=length;
    int target;

    //while(gas>0)
    //{
    	int gas=1;
        for(int i=gas;i<length;i++)
        {
            target=arr[i];
            int pos=i;
            while(pos>0 && target<arr[pos-gas])//后移动数据
            {
                arr[pos]=arr[pos-gas];
                pos-=gas;
            }
            arr[pos]=target;

        //}
        //gas=gas/2;
    }
}

5.堆排序

堆排序是一种选择排序
a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
参考堆排序
参考视频
在这里插入图片描述

void HeapAdjust(int *arr,int begin,int length)
{
    int temp=arr[begin];//将首元素保持起来

    for(int i=2*begin+1;i<length;i=i*2+1)//从i结点的左子结点开始,也就是2i+1处开始
    {
        if(i+1<length && arr[i]<arr[i+1])//取出左右孩子中较大的元素,该结点的标号为i
            i++;
        if(temp>=arr[i])//temp是最大值,不用调整
            break;
        else
        {
            arr[begin]=arr[i];//根取最大值

            begin=i;//对最大值位置在经行操作
        }
    }
    arr[begin]=temp;
    
}


void HeapSort(int *arr,int length)
{
    for(int i=length/2-1;i>=0;i--)//构建一个大顶堆,[(length-1)/2是从有孩子结点的最后一个结点开始]
    {
        HeapAdjust(arr,i,length);   //将[0,1,2...length]的元素构建大顶堆
    }

    for(int i=length-1;i>0;i--)//逐步将每个根值与末尾元素交换
    {
        //交换数据
        int temp=arr[0];
        arr[0]=arr[i];
        arr[i]=temp;
        HeapAdjust(arr,0,i);//将[0,1,2,3...length]的元素经行重新堆排序
    }
}

6.归并排序

依次调用

    void MergeSort(int arr[],int length);
    void MSort(int arr[],int begin,int end);
    void Merge(int arr[], int begin,int mid,int end);

MergeSort归并排序–>MSort排序–>Merge归并

//=============================归并排序记忆版本===========================================
/*
    归并排序主要由如下的三个函数组成
    void MergeSort(int arr[],int length);
    void MSort(int arr[],int begin,int end);
    void Merge(int arr[], int low,int mid,int high);

*/

void Merge3(int arr[],int begin,int mid,int end)
{
    int* tempArr=(int *)malloc((end-begin+1)*sizeof(int));
    // int length=end-begin+1;
    // int tempArr[length];
    int i=begin;//前半部分
    int j=mid+1;//后半部分
    int k=0;//前半数据和后半数据,合并到新的数组的下标
    while(i<=mid && j<=end)
    {
        if(arr[i]<=arr[j])
        {
            tempArr[k++]=arr[i++];
        }
        else
        {
            tempArr[k++]=arr[j++];
        }
    }
    while(i<=mid)
    {
        tempArr[k++]=arr[i++];
    }
    while(j<=end)
    {
        tempArr[k++]=arr[j++];
    }
    
    //将tempArr中排序完成的数据,从新拷贝到
    //begin到end的区间上去
    for(i=begin,k=0;i<=end;i++,k++)
    {
        arr[i]=tempArr[k];
    }

    delete[] tempArr;

}

void MSort3(int arr[],int begin,int end)
{
    if(begin>=end)
        return ;
    int mid=(begin+end)/2;
    MSort3(arr,begin,mid);
    MSort3(arr,mid+1,end);
    Merge3(arr,begin,mid,end);
}

void Mergesort3(int arr[],int length)
{
    MSort3(arr,0,length-1);
}

7.快速排序

通过一趟排序将待排序记录分割成独立的两部分,其中一部分的关键字大于另一部分的关键字,然后对这两部分在继续进行排序,最终达到整个序列有序的目的
和归并排序类似,快速排序算法也分为三部分,依次调用

    void QuickSort(int arr[],int length);
    void QSort(int arr[],int begin,int end);
    void Partition(int arr[], int begin,int end);

QuickSort快速排序–>QSort排序–>Partition位置

int Partition0(int arr[], int begin,int end)
{
    int pivotkey=arr[begin];//其实位置作为枢轴

    while(begin<end)
    {
        while(begin<end && arr[end]>=pivotkey)
            end--;
        
        //交换数据
        int temp=arr[begin];
        arr[begin]=arr[end];
        arr[end]=temp;

        while(begin<end && arr[begin]<=pivotkey)
            begin++;
        
        //交换数据
        temp=arr[begin];
        arr[begin]=arr[end];
        arr[end]=temp;
    }
    return begin;
}

//优化
int Partition(int arr[], int begin,int end)
{
    int pivotkey=arr[begin];//其实位置作为枢轴
    while(begin<end)
    {
        while(begin<end && arr[end]>=pivotkey)
            end--;
        
        //交换数据
        arr[begin]=arr[end];

        while(begin<end && arr[begin]<=pivotkey)
            begin++;
        
        //交换数据
        arr[end]=arr[begin];
    }
    arr[begin]=pivotkey;
    return begin;
}


void QSort(int arr[],int begin,int end)
{
    int pivot;
    if(begin>=end)
        return;
    pivot=Partition(arr,begin,end);
    QSort(arr,begin,pivot-1);
    QSort(arr,pivot+1,end);
}


void QuickSort(int arr[],int length)
{
    QSort(arr,0,length-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值