• 学习记录:排序专题


    1. 直接插入排序

    顾名思义,实现排序的方式就是插入。下面由从小到大的顺序进行一次排序。

    1. 确定一个已经有序的序列,这里先选第一个元素为有序(毕竟只有一个元素)

    2. 从无序的第一个元素开始比较,有两种情况:

      1. 无序序列的第一个元素大于有序数列的最后一个元素,就说明这个元素在有序序列中是最大的,所以它的位置是正确的,无需任何操作。
      2. 无序序列的第一个元素小于有序数列的最后一个元素,该元素位置错误,从有序序列开始遍历,直到找到正确的位置。
        将已经遍历过的元素向后移一位,将该元素插入。

    重复这种操作,直到全部有序

    //代码如下
    void InsertSort(int *arr,int length)
    {
    	int Temp;//用于记录无序序列的第一个元素
    	for (int i=1;i<length;i++)
    	{
    		if (arr[i-1]<=arr[i])//第一种情况
    			continue;
    		else//第二种情况
    		{
    			Temp=arr[i];//记录
    			for (int j=0;j<i;j++)
    			{
    				if (Temp<arr[j])//找到正确的位置
    				{
    					for (int k=i;k>=j;k--)//该循环用于将数组后移
    						arr[k]=arr[k-1];
    					arr[j]=Temp;//将该元素插入
    					break;//退出循环
    				}
    			}
    		}
    	}
    }
    
    void InsertSort(int *arr,int length)
    {
    	int Temp,j;
    	for (int i=1;i<length;i++)
    	{
    		Temp=arr[i];
    		if (arr[i-1]>Temp)
    		{
    			for (j=i-1;Temp<arr[j]&&j>=0;j--)
    				arr[j+1]=arr[j];
    			arr[j+1]=Temp;
    		}
    	}
    	for (int i=0;i<length;i++)
    		cout<<arr[i]<<" ";
    }
    

    2. 折半插入

    折半插入排序是对于插入排序的一个改良版本,将寻找适合插入位置的过程改为了运用二分来进行查找,相比直接插入排序要快一点

    void Binary_InsertSort(int arr[],int length)
    {
        for (int i=1;i<length;i++)
    	{
    		int left=0,right=i-1,m;
    		while (left<=right) //折半查找寻找正确位置
    		{
    			m=(left+right)/2;
    			if (arr[m]>arr[i])
    				right=m-1;
    			else
    				left=m+1;
    		}
    		int temp=arr[i];
    		for (int j=i;j>right+1;j--) //后移
    			arr[j]=arr[j-1];
    		arr[right+1]=temp; //插入
    	}
    }
    

    3. 二路插入排序

    二路插入排序是对折半插入的进一步改进,减少了交换的次数,其实现方法是多开一个同样大小的数组,再将它想象为一个循环的数组(类似于约瑟夫环),再利用两个指针(并不是真的指针,只是指明数的位置)记录在新建的数组中的最大数与最小数,来减少交换次数。

    插入排序:二路插入,这一篇博客写的很好

    void InsertSort2(int *a,int n)
    {
    	int first=0,last=0;
    	int *b=new int[n];
    	b[0]=a[0];
    	for (int i=1;i<n;i++)
    	{
    		if (a[i]<=b[first])
    		{
    			first = (first-1+n)%n;
    			b[first]=a[i];
    		}
    		else if (a[i]>=b[last])
    		{
    			last++;
    			b[last]=a[i];
    		}
    		else
    		{
    			int left=first, right=last,m,tem;
    			while (left!=right) //折半查找寻找正确位置
    			{
    				tem=(right-left+n)%n;
    				m=(left+tem/2)%n;
    				if (a[i] < b[m])
    					right=m;
    				else
    					left=(m+1)%n;
    			}
    			for (int j=last+1;j!=left;j=(j-1+n)%n)
    				b[j]=b[(j-1+n)%n];
    			b[left] = a[i];
    			last++;
    		}
    	}
    	for (int i=0;i<n;i++)
    		a[i]=b[(i+first)%n];
    	delete []b;
    }
    

    4. 希尔排序

    void ShellSort(int *arr,int length)
    {
        for(int gap=length/2;gap>0;gap/=2)
        {
            for(int i=gap;i<length;++i)
            {
                int j=i;
                while(j-gap>=0 && arr[j-gap]>arr[j])
                {
                	swap(arr[j],arr[j-gap]);
                    j=j-gap;
                }
            }
        }
    }
    

    5. 冒泡排序

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

    6. 改进冒泡排序

    void newBubbleSort(int *arr,int length)
    {
    	int flag=length,k;
    	for (int i=0;i<flag;i++)
    	{
    		k=flag;
    		flag=0;
    		for (int j=0;j<k;j++)
    		{
    			if (arr[j]<arr[j+1])
    			{
    				flag=j;
    				swap(arr[j],arr[j+1]);
    			}
    		}
    	}
    }
    

    7. 鸡尾酒排序

    void Cocktail_Sort(int *arr,int length)
    {
    	int low=0;
    	int high=length;
    	int flag=1,bound=1;
    	while (flag)
    	{
    		flag=0;
    		for (int i=low;i<length;i++)
    		{
    			if (arr[i]>arr[i+1])
    			{
    				swap(arr[i],arr[i+1]);
    				flag=1;
    				bound=i;
    			}
    		}
    		high=bound;
    		for (int i=high;i>low;i--)
    		{
    			if (arr[i]<arr[i-1])
    			{
    				swap(arr[i],arr[i-1]);
    				flag=1;
    				bound=i;
    			}
    		}
    		low=bound;
    	}
    }
    

    8. 快速排序

    void Quick_Sort(int *arr,int beginn,int endn)
    {
    	if (beginn<endn)
    	{
    		int left=beginn;
    		int right=endn;
    		int mid=arr[beginn];
    		while (left<right)
    		{
    			while (left<right&&arr[right]>=mid)
    				right--;
    			if (left<right)
    				arr[left++]=arr[right];
    			while (left<right&&arr[left]<=mid)
    				left++;
    			if (left<right)
    				arr[right--]=arr[left];
    		}
    		arr[left]=mid;
    		Quick_Sort(arr,beginn,left-1);
    		Quick_Sort(arr,right+1,endn);
    	}
    }
    

    9. 简单选择排序

    初见感觉这个算法异常的暴力。核心思想就是遍历一遍找最大值or最小值,重复执行的同时范围也在随之减少(因为每遍历一趟减少了最值),直到数组有序。

    概括一下:每一趟在后面 n-i 个待排记录中选取关键字最小的记录作为第 i 个值得记录,两层循环O(n^2)时间复杂度结束

    void Simple_Select_Sort(int *arr,int istart,int iend)
    {
    	for (int i=0;i<iend-1;i++)
    	{
    		int temp=i;
    		for (int j=i;j<iend;j++)
    			if (arr[j]<arr[temp])
    				temp=j;
    		swap(arr[temp],arr[i]);
    	}
    }
    

    10. 堆排序

    堆有点二叉树的意思,而且我觉得在之前所有基础排序算法之中都是比较难的一种算法。

    专门写了篇博客记录一下,顺带学了学怎么做示意图~堆排序简介

    void HeapAdjust(int *arr,int top,int range)//arr为数组首地址,top为需要进行恢复的元素下标,range就是范围啦
    {
    	for (int i=top*2;i<=range;i*=2)//为什么是*2?因为要获得子节点的下标
    	{
    		if (i<range&&arr[i]<arr[i+1])
    			i++;//找到两个子节点中最大的元素的下标
    		if (arr[top]>=arr[i])
    			break;//不需要交换就退出
    		swap(arr[top],arr[i]);//较大的子节点上移给父节点
    		top=i;//现在要处理的点就是子节点
    	}
    }
    void InitHeap (int *arr,int length)
    {
    	for (int i=length;i>=1;i--)
    		arr[i]=arr[i-1];
    	for (int i=length/2;i>0;i--)
    		HeapAdjust(arr,i,length);
    }
    void HeapSort(int *arr,int length)
    {
    	InitHeap(arr,length);
    	for (int i=length;i>0;i--)
    	{
    		swap(arr[i],arr[1]);
    		HeapAdjust(arr,1,i-1);
    	}
    	for (int i=0;i<length;i++)
    		arr[i]=arr[i+1];
    }
    

    PS

    int main()
    {
    	int length=20;
    	int arr[length];
    	srand((unsigned)time(NULL));
    	clock_t start = clock();  //时间起始
    	for (int i=0;i<length;i++)
    	{
    		arr[i]=rand()%100;
    		printf("%5d",arr[i]);
    	}
    	printf("
    ");
    	ShellSort(arr,length);
    	clock_t end   = clock(); //时间测试结束
    	cout<<end - start<<endl; //计算打印出运行时间,单位ms
    	for (int i=0;i<length;i++)
    		printf("%5d",arr[i]);
    	return 0;
    }
    
  • 相关阅读:
    thinkPHP入门之二
    thinkPHP入门
    斐波那契数列,冒泡排序,选择排序,数组去重
    jquery-懒加载插件
    本地存储之cookie
    javascript的快速排序法
    [luogu2165 AHOI2009] 飞行棋 (枚举)
    [luogu2576 SCOI2010] 幸运数字 (容斥原理)
    [luogu2587 ZJOI2008] 泡泡堂 (贪心)
    [luogu2602 ZJOI2010] 数字计数 (数位dp)
  • 原文地址:https://www.cnblogs.com/Salty-Fish/p/12469385.html
Copyright © 2020-2023  润新知