十大排序算法解析及实现

堆排序

计数排序

桶排序

基数排序

总结

排序算法 平均时间复杂度 最好情况 最坏情况 空间复杂度 稳定性
冒泡排序 O(n^{2}) O(n) O(n^{2}) O(1) 稳定
插入排序 O(n^{2}) O(n) O(n^{2}) O(1) 稳定
希尔排序 O(n^{2/3}) O(n) O(n^{2}) O(1) 不稳定
选择排序 O(n^{2}) O(n^{2}) O(n^{2}) O(1) 不稳定

一、冒泡排序(Bubble Sort)

1.算法描述

平均时间复杂度:O(n^{2})
空间复杂度:O(1)

  • 从前向后依次检查每一对相邻元素,一旦发现逆序(前面一个元素大于后面)即交换二者的位置;
  • 完成一趟扫描之后,最大元素抵达应处的位置;
  • 对余下的元素重复上述步骤。

2.动图

3.实现

void bubbleSort(int arr[], int n)
{
	for (int i = 0; i < n - 1; i++) //外循环为排序趟数,n个数进行n-1趟
	{
		bool sorted = true; //整体有序标志
		for (int j = 0; j < n - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;

				sorted = false;
			}
		}

		if (sorted) // 一旦经过某趟扫描之后未发现任何逆序的相邻元素,意味着排序任务完成。
			break;  // 算法终止
		
	}
}

二、插入排序(Insertion Sort)

1.算法描述

平均时间复杂度:O(n^{2})
空间复杂度:O(1)

  • 整个序列包括有序的前缀和无序的后缀
  • 反复的将后缀的首元素移至前缀中

2.动图

3.实现

void insertionSort(int arr[], int n)
{
	
	for (int i = 1; i < n; i++)
	{
		for (int j = i; j > 0; j--) //有序前缀[0, i) 
		{
			// 后序的首元素arr[i] 找到合适的插入位置
			if (arr[j] < arr[j - 1])
			{
				int temp = arr[j];
				arr[j] = arr[j - 1];
				arr[j - 1] = temp;
			}
			else
				break;
		}
		// 内存for结束后 有序前缀范围扩大至[0, i]
	}
		
}

三、希尔排序(Shell Sort)

1.算法描述

平均时间复杂度:O(n^{2})
空间复杂度:O(1)

取一个递增的增量序列:H =\left \{ 1, w_{1}, w_{2},..., w_{k}\right \}

for(t = k; t > 0; t--)

{

        使用增量w_{t}的一趟排序之后,间隔为w_{t}的元素都被排序了

}

2.动图

3.实现

增量序列设计与选择的方法有很多,这里选择\left \{ 1,2,4,8,...,2^{k} \right \}

void shellSort(int arr[], int n)
{
	
	int increment = n / 2; //增量

	while (increment >= 1)
	{
		for (int i = increment; i < n; i++)
		{
			for (int j = i - increment; j >= 0; j -= increment)
			{
				// 将 a[i] 插入到分组正确的位置
				// 这里并不是处理完一个增量序列再处理另一个的
				// 是按照数组循序处理的 arr[0] arr[1] ……
				/*
				j = i - increment;
				i = j + increment;
				*/
				if (arr[j] > arr[j + increment])
				{
					int temp = arr[j];
					arr[j] = arr[j + increment];
					arr[j + increment] = temp;
				}
			}
		}
		increment /= 2;
	}

}

四、选择排序(Selection Sort)

1.算法描述

平均时间复杂度:O(n^{2})
空间复杂度:O(1)

  • 分为有序前缀 和无序后缀
  • 并且前缀的值不大于后缀
  • 每次从后缀中选出最小者,并作为最大元素移入前缀中

2.动图

3.实现

void selectSort(int arr[], int n)
{
	
	for (int i = 0; i< n - 1; i++)
	{
		//有序前缀[0, i)
		int index = i;  
		for (int j = i + 1; j < n; j++)
			if (arr[j] < arr[index]) //寻找无序区内的最小值  
				index = j;

		if (index != i) //将其移至有序区末尾
		{
			int tmp = arr[index];
			arr[index] = arr[i];
			arr[i] = tmp;
		}
		//一轮外循环后,有序前缀[0, i]
	}

}

五、快速排序(Quick Sort)

1.算法描述

平均时间复杂度:O(n\log n)
空间复杂度:O(\log n)

int Partation(int arr[], int lo, int hi)
{
	int pivot = arr[lo];
	while (lo < hi)
	{
		while ((lo < hi) && (pivot <= arr[hi]))
			hi--;
		arr[lo] = arr[hi];
		while ((lo < hi) && (arr[lo] <= pivot))
			lo++;
		arr[hi] = arr[lo];
	}
	arr[lo] = pivot;
	return lo;
}

void quickSort(int arr[], int lo, int hi)
{
	if (lo < hi)
	{
		int mi = Partation(arr, lo, hi);
		quickSort(arr, lo, mi - 1);
		quickSort(arr, mi + 1, hi);
	}
}

六、归并排序(Merge Sort)

void merge(int arr[], int lo, int mi, int hi, int temp[])
{
	int i = lo; // [lo, mi] [mi + 1, hi]
	int j = mi + 1;
	int t = 0;
	
	while ((i <= mi) && (j <= hi))
	{
		if (arr[i] <= arr[j])
			temp[t++] = arr[i++];
		else
			temp[t++] = arr[j++];
	}

	while(i <= mi)
		temp[t++] = arr[i++];
	while(j <= hi)
		temp[t++] = arr[j++];

	t = 0;
	while (lo <= hi)
	{
		arr[lo++] = temp[t++];
	}
}
void mergeSort(int arr[], int lo, int hi, int temp[])
{
	if (lo < hi)
	{
		int mi = lo + (hi - lo) / 2;
		mergeSort(arr, lo, mi, temp);
		mergeSort(arr, mi + 1, hi, temp);
		merge(arr, lo, mi, hi, temp);
	}
}

七、桶排序(Bucket Sort)

void bucketSort(vector<int>& vec)  
{  
    int length=vec.size();  
    vector<int> buckets(length,0);//准备一堆桶,容器的下标即待排序数组的键值或键值经过转化后的值  
    //此时每个桶中都是没有放值的,所以都是0  

    for(int i=0;i<length;++i)  
    {  
        buckets[vec[i]]++;//把每个值放入到对应的桶中  
    }  

    int index=0;  
    for(int i=0;i<length;++i)  
    {//把值取出,空桶则直接跳过  
        for(int j=0;j<buckets[i];j++)  
        {  
            vec[index++]=i;  
        }  
    }  
}  

猜你喜欢

转载自blog.csdn.net/u014128608/article/details/93104060