典型排序算法之:冒泡排序/直接插入排序/希尔排序/选择排序/快速排序

// sort_test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"


void swap(int&a, int &b)
{
	int temp = b;
	b = a;
	a = temp;
}

void print_arr(int* arr, int arr_len)
{
	for (int i = 0; i < arr_len; i++)
	{
		printf("%d ", arr[i]);
	}
	puts("");
}

/* 【冒泡排序】
 * 遍历数组中的每个元素,并比较相邻的两个元素,如果两个元素的位置不对,就将其位置调换过来。这样,在遍历了一次之后,最大/最小的元素
 * 一定升到了最上面。而我们重复遍历N次,就可以将所有的元素排序号。这样每次将最大的升到最上面,就好像泡沫冒上来一样,因此叫冒泡排序。
 * 
 * 稳定性:稳定
 *
 * 时间复杂度: O(n^2)
 */
void bubble_sort(int* arr, int arr_len)
{
	for (int i = 0; i < arr_len - 1; i++)
	{
		bool sorted = true;
		for (int j = 0; j < arr_len -1 - i; j++)
		{
			if (arr[j] > arr[j+1])
			{
				sorted = false;
				swap(arr[j], arr[j+1]);
			}
		}

		if (sorted)
		{
			break;
		}
	}
}

/* 【直接插入排序】
 * 依次把数组的前部分看做是排序的数组,然后把后面的数组往已经排序号的部分插入。插到最后一个元素,那么整个数组就是排序号的
 *
 * 稳定性:稳定
 *
 * 时间复杂度:O(n^2)
 */
void insert_sort(int* arr, int arr_len)
{
	for (int i = 1; i < arr_len; i++)
	{
		int val = arr[i];
		int j = i - 1;
		for (; j >= 0; j--)
		{
			if (arr[j] > val)
			{
				arr[j + 1] = arr[j];
			}
			else
			{
				break;
			}
		}
		arr[j + 1] = val;
	}
}


/* 【希尔排序】
 * 希尔排序是在插入排序的基础上发展的来的算法。希尔排序基于插入排序的如下特征:
 * 在数组基本有序的时候,算法的效率很高;在完全排序的数组下,可以达到线性的效率。
 * 希尔排序又称为缩小增量插入排序: 希尔排序先取一个数值作为增量,将数组分组,再将分组中的元素按照插入排序,在依次缩小增量。当
 * 增量缩小到1时,算法结束,排序完毕。
 * 希尔排序增量的选择可以有很多中,其中比较常见的是希尔增量,即每次选取上个增量的一半。
 *
 * 稳定性:不稳定,虽然一次直接插入排序是稳定的,但是在增量不同时,不同的元素在不同的组中排序,可能会打乱其相对位置。
 *
 * 时间复杂度:依据增量的不同,时间复杂都也不同。时间复杂度在范围O(n*log2n) ~ O(n^2) 之间,在希尔增量下时间复杂度为O(n^2)
 */
void shell_sort(int* arr, int arr_len)
{
	for (int div = arr_len / 2; div >= 1; div /= 2)	// 逐渐缩小增量
	{
		for (int i = 0; i < div; i++)	// 将数组分成div个组
		{
			// 对每个分组进行直接插入排序
			for (int j = i + div; j < arr_len; j += div) 
			{
				int val = arr[j];
				int k = j - div;
				for (; k >= 0; k -= div)
				{
					if (arr[k] > val)
					{
						arr[k + div] = arr[k];
					}
					else
					{
						break;
					}
				}
				arr[k + div] = val;
			}
		}
	}
}


/* 【选择排序】
 * 选择排序是每次选择最大/最小的元素,放在未排序的部分的末尾或i这起始。这样,当所有的元素都进行了算则之后,就得到了一个有序的数组。
 *
 * 稳定性:不稳定:比如有数组{3, 3, 2},我们第一次找到最小元素2的时候,将他和第一个3交换,这样,两个3的顺序就变化了。
 *
 * 时间复杂度:O(n^2)
 */
void selection_sort(int *arr, int arr_len)
{
	for (int i = 0; i < arr_len; i++)
	{
		int min_idx = i;
		for (int j = i + 1; j < arr_len; j++)
		{
			if (arr[j] < arr[min_idx])
			{ 
				min_idx = j;
			}
		}

		swap(arr[i], arr[min_idx]);
	}
}


void quick_sort_core(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}

	int i = left, j = right;
	int key = arr[left];

	while (i < j)
	{
		while (arr[j] >= key && j > i) { j--; }
		arr[i] = arr[j];

		while (arr[i] <= key && i < j) { i++; }
		arr[j] = arr[i];
	}
	arr[i] = key;

	quick_sort_core(arr, left, i - 1);
	quick_sort_core(arr, i + 1, right);
}


/* 【快速排序】
 * 快速排序采用了递归的思想,每次将数组分成两个部分,其中一部分一定大于某一个数,而两外一部分一定小于某一个数。
 * 并采用同样的方法对两个数组递归,当递归到数组只有两个元素或者一个元素的时候,数组就有序了。
 *
 * 稳定性:不稳定
 *
 * 时间复杂度:O(nlog(n))
 */
void quick_sort(int* arr, int arr_len)
{
	quick_sort_core(arr, 0, arr_len - 1);
}


int main()
{
	int a[] = { 19, 45, 23, 1, 27, 123, 455, 12 };
	//int a[] = { 3, 1, 2 };
	int arr_len = sizeof(a) / sizeof(int);

	//bubble_sort(a, arr_len);
	//insert_sort(a, arr_len);
	//quick_sort(a, arr_len);
	//selection_sort(a, arr_len);
	shell_sort(a, arr_len);

	print_arr(a, arr_len);

	system("pause");
	
    return 0;
}

 

你可能感兴趣的:(典型算法)