排序算法--一些算法的总结


简单插入:整个序列分为有序区和无序区,取第一个元素作为初始有序区,然后第二个开始,依次插入到有序区的合适位置,直到排好序。第一个for循环对从第二个开始的所有的数字遍历,嵌套的for循环是每次遍历数字时都取无序区的一个元素与有序区的元素比较,如果比有序区的要小则交换,直到合适的位置。插入排序的时间复杂度最好的情况是已经是正序的序列,只需比较(n-1)次,时间复杂度为O(n),最坏的情况是倒序的序列,要比较n(n-1)/2次,时间复杂度为O(n^2 ) ,平均的话要比较时间复杂度为O(n^2 )。插入排序是一种稳定的排序方法,排序元素比较少的时候很好,大量元素便会效率低下。

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

希尔(插入):(Shell Sort),也称为递减增量排序算法,是插入排序的一种高速而稳定的改进版

希尔排序是一种按照增量排序的方法。其中增量值是小于n的正整数。先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

(1)初始增量为3,该数组分为三组分别进行排序。(初始增量值原则上可以任意设置(0<gap<n),没有限制)

(2)将增量改为2,该数组分为2组分别进行排序。

(3)将增量改为1,该数组整体进行排序。

void shell_sort(int a[], int n)  
{  
    int gap;  
    for(gap = 3; gap >0; gap--){  
        for(int i=0; i<gap; i++){  
            for(int j = i+gap; j<n; j=j+gap){  
                if(a[j]<a[j-gap])  {  
                    int temp = a[j];  
                    int k = j-gap;  
                    while(k>=0&&a[k]>temp){  
                        a[k+gap] = a[k];  
                        k = k-gap;  
                    }  
                    a[k+gap] = temp;  
                }  
            }  
       }  
    }  
}  
简单选择:每次找到最小的交换

void SimSelSort(int *p, int length)
{
    int i, j, min;
    for (i = 0; i < length - 1; i++)
    {
        min = i;         
        for (j=i+1;j<=length-1;j++)
            if (p[j] < p[min])
                min = j;         
        swap(p[i], p[min]);
    }
}

堆(选择):堆的结构类似于完全二叉树,每个结点的值都小于或者等于其左右孩子结点的值,或者每个节点的值都大于或等于其左右孩子的值堆排序过程将待排序的序列构造成一个堆,选出堆中最大的移走,再把剩余的元素调整成堆,找出最大的再移走,重复直至有序堆排序的时间复杂度最好到最坏都是O(nlogn),较多元素的时候效率比较高。

void Heapify(int arr[], int first, int end)
{
    int father = first;
    int son = father * 2 + 1;
    while(son < end)
	{
        if(son + 1 < end && arr[son] < arr[son+1]) ++son;
        if(arr[father] > arr[son]) break;
        else 
		{
			swap(arr[father],arr[son]);
            father = son;
            son = 2 * father + 1;
        }
    }
}
void HeapSort(int arr[],int len)
{
    int i;
    for(i = len/2 - 1; i >= 0; --i)
        Heapify(arr,i,len);
    for(i = len - 1;i > 0;--i)
    {
		swap(arr[i],arr[0]);
    	Heapify(arr,0,i);
    }
}

冒泡(交换):比较相邻的元素,如果反序则交换,过程也是分为有序区和无序区,初始时有序区为空,所有元素都在无序区,经过第一趟后就能找出最大的元素,然后重复便可。第一个for循环是遍历所有元素,第二个for循环是每次遍历元素时都对无序区的相邻两个元素进行一次比较,若反序则交换。时间复杂度最坏的情况是反序序列,要比较n(n-1)/2次,时间复杂度为O(n^2 ),最好的情况是正序,只进行(n-1)次比较,不需要移动,时间复杂度为O(n),而平均的时间复杂度为O(n^2 )。冒泡排序是一种稳定的排序算法,元素较少时效率比较高。

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

快排(交换):快速排序首先选一个基准值,将待排序记录划分成独立的两部分,左侧的元素均小于基准值,右侧的元素均大于或等于基准值,然后对这两部分再重复,直到整个序列有序。过程是和二叉搜索树相似,就是一个递归的过程。快速排序时间复杂度的最好情况和平均情况一样为O(nlog2 n),最坏情况下为O(n^2 ),这个看起来比前面两种排序都要好,但是这是不稳定的算法,并且空间复杂度高一点( O(nlog2 n),而且快速排序适用于元素多的情况。

int getPartion(int arr[], int low, int high){
 	int key=arr[low];
 	while(low < high)
	{
  		while(low <high && key <= arr[high]) 
		  --high;
		swap(arr[low],arr[high]); 
  		while(low < high && key >= arr[low]) 
		  ++low;
		  swap(arr[low],arr[high]);
	}
	return low;
}
void QuickSort(int arr[], int low, int high)
{
	if(low<high)
	{
		int key = getPartion(arr,low,high);
 		QuickSort(arr,low,key-1);
 		QuickSort(arr,key+1,high);		
	}
} 
合并:归并排序的基本思想是将若干个序列进行两两归并,直至所有待排序记录都在一个有序序列为止。每次合并就是一次递归

首先,将一整个序列分成两个序列,两个会分成4个,这样分下去分到最小单位,然后开始合并。归并排序的时间复杂度都是O(nlogn),并且适用于元素较多的时候排序。

void Merge(int arr[], int reg[], int start, int end) 
{
    if (start >= end)return;
    int len = end - start, mid = (len >> 1) + start;
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    Merge(arr, reg, start1, end1);
    Merge(arr, reg, start2, end2);
    int k = start;
    while (start1 <= end1 && start2 <= end2)
        reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
    while (start1 <= end1)
        reg[k++] = arr[start1++];
    while (start2 <= end2)
        reg[k++] = arr[start2++];
    for (k = start; k <= end; k++)
        arr[k] = reg[k];
}

void MergeSort(int arr[], const int len) 
{
    int  reg[len];
    Merge(arr, reg, 0, len - 1);
}

基数:计数排序则是打表或是哈希思想最简单的实现。首先将所有待比较树脂统一为统一位数长度,接着从最低位开始,依次进行排序。
1. 按照个位数进行排序。
2. 按照十位数进行排序。
3. 按照百位数进行排序。

排序后,数列就变成了一个有序序列。为什么要从个数开始比较,低位是有序的,高位中如果有相同的值,则只需在保持稳定的前提下对高位进行排序,结果自然有序。

void countSort(vector<int>& vec,int exp)  
{  
    vector<int> range(10,0);    
    int length=vec.size();  
    vector<int> tmpVec(length,0);    
    for(int i=0;i<length;++i)  
        range[(vec[i]/exp)%10]++;  
    for(int i=1;i<range.size();++i)  
        range[i]+=range[i-1];
    for(int i=length-1;i>=0;--i)  
    {  
        tmpVec[range[(vec[i]/exp)%10]-1]=vec[i];  
        range[(vec[i]/exp)%10]--;  
    }  
    vec=tmpVec;  
}    
void radixSort(vector<int>& vec)  
{  
    int length=vec.size();  
    int max=-1;  
    for(int i=0;i<length;++i)   
        if(vec[i]>max)  
            max=vec[i];  
    for(int exp=1;max/exp>0;exp*=10)  
        countSort(vec,exp);  
}   

猜你喜欢

转载自blog.csdn.net/sinat_21026543/article/details/79826293