5种常见排序方法深度剖析

(一)直接插入排序

直接插入排序的思想是从下下标为1的数开始每遍历一个数,就往前比较直到插入合适的位置下面画图说明

# include<iostream>

# include<cassert>
using namespace std;
size_t *InsertSort1(size_t *array, size_t size)//直接插入排序双循环写法
{
assert(array);
for (int i = 1; i < size; i++)
{
size_t temp = array[i];
int j = i - 1;
for (; j >= 0 && temp<array[j]; j--)//查找合适的插入位置
{

array[j + 1] = array[j];//往后挪动
}
array[j+1] = temp;//找到合适的插入位置
}
return array;
}
size_t* InsertSort2(size_t *array, size_t size)//直接插入排序while循环写法
{
assert(array);
for (size_t i = 1; i < size; i++)
{
size_t index = i;
size_t temp = array[index];
size_t end = index - 1;
while (end>0 && temp < array[end])
{
array[end + 1] = array[end];
end--;
}


array[end+1] = temp;
}
return array;

}

//(二)希尔排序

size_t *ShellSort(size_t *array, size_t size)//希尔排序
{
assert(array);
int gap = size;
while (gap > 1)
{
gap = gap / 3 + 1;//定义一个间距
for (int i = 0; i < size; i++)//将gap换成1就是直接排序的部分
{
int index = i;
int temp = array[index];
int end = index - gap;
while (end>0 && temp < array[end])
{
array[end + gap] = array[end];
end -= gap;
}
array[end + gap] = temp;
}
}
return array;
}
void Print(size_t *array, size_t size)
{
for (size_t i = 0; i < size; i++)
{
cout << array[i] << " ";
}
cout << endl;
}
void AdjustDown(size_t *array, size_t size, int root)//向下调整堆
{
assert(array);
int parent = root;
int child = root * 2 + 1;
while (child < size)
{
if (child + 1 < size&&array[child] < array[child + 1])//这里要建大堆,使堆顶元素成为最大值
{
child++;
}
if (array[child]>array[parent])
{
swap(array[child], array[parent]);
parent = child;
child = child * 2 + 1;
}
else
{
break;
}
}


}

//(三)堆排序

size_t *HeapSort(size_t*array, size_t size)//堆排序
{
assert(array);
for (int i = (size - 2) / 2; i >= 0; --i)//对所给的完全二叉树建一个大顶堆
{
AdjustDown(array, size, i);
}
for (int i = size - 1; i > 0; --i)//每次将堆顶元素和最后一个元素交换,缩小size的范围
{
swap(array[0], array[i]);    //然后从a[0]开始向下调整即可,这样又能将最大的元素调整到a[0]
AdjustDown(array, i, 0);     //的位置,如此反复便将所有的元素升序排列
}
return array;
}
size_t *BubleSort(size_t*array, size_t size)//冒泡排序
{
assert(array);
for(int i = 0; i < size; i++)
{
for (int j = size - 1; j > i; j--)//注意边界条件
{
if (array[j] < array[j - 1])
{
swap(array[j], array[j - 1]);
}
}
}
return array;
}
size_t * SelectionSort(size_t *array, size_t size)//选择排序从,后面的无序区依次选出最小的数和
{
assert(array);                                 //前面[0 size)分别交换用一个min记录最小的下标。
for (int i = 0; i < size-1; i++)
{
int min = i;
for (int j = i+1; j<size; j++)
{
if (array[min] > array[j])
{
min = j;
}
}
swap(array[i],array[min]);
}
return array;
}
int main()
{
size_t array[10] = { 98, 5, 2, 78, 12, 21, 55, 12, 15, 1 };
size_t size = 10;
/*size_t *p1=InsertSort1(array, 10);
Print(p1, 10);
size_t *p2=InsertSort2(array, 10);
Print(p2, 10);
size_t *p3 = ShellSort(array, 10);
Print(p3, 10);
size_t *p4 = HeapSort(array, 10);
Print(p4, 10);*/
//size_t *p5 = BubleSort(array, 10);
//Print(p5, 10);
//size_t *p6 = SelectionSort(array, 10);
//Print(p6, 10);

}

(四)快速排序和归并排序

# include<iostream>
# include<cassert>
# include<stack>
using namespace std;
int  ThreeGetKey(int *a, int left, int right)//三数取中法的优化key
{
	int mid = left + (right - left) / 2;
	if (a[left] < a[right])
	{
		if (a[mid] < a[left])
		{
			return a[left];
		}
		else if (a[mid] < a[right])
		{
			return a[mid];
		}
		else
		{
			return a[right];
		}
	}
	else{
		if (a[mid] < a[right])
		{
			return a[right];
		}
		else if (a[mid] < a[left])
		{
			return a[mid];
		}
		else
		{
			return a[left];
		}
	}
}
int PartionSort1(int *a, int left, int right)//快速排序部分排序版本1
{
	int begin = left;
	int end = right;
	int key = ThreeGetKey(a, left, right);//优化后,不优化为a[right];
	while (begin < end)
	{
		while (a[begin]<= key&&begin < end)//这两个while循环的先后顺序一定不能交换
		{
			++begin;
		}
		while (a[end] >= key&&begin < end)
		{
			end--;
		}
		
		if (begin < end)
		{
			swap(a[begin], a[end]);
		}
	}
	if (a[begin]>key)
	{
		swap(a[begin], a[right]);
		return begin;
	}
	else
	{
		return right;
	}
}
int PartionSort2(int *a, int left, int right)//快速排序部分排序版本2
{
	int key = a[right];
	int cur = left;
	int prev = left - 1;
	while (cur < right)
	{
		if (a[cur] < key && ++prev != cur)//cur一直向后走,只要这个值比key小
			               //(说明前面prev所指的值都是比key大的值)prev就向后走一步,
						   //若prev和cur不相等就交换
		{
			swap(a[cur], a[prev]);
		}
		cur++;
	}
	swap(a[++prev], a[right]);
	return prev;
}
void QuckSort2(int *a, int left, int right)//快速排序的非递归方法
{
	if (left < right)
	{
		stack<int> s;
		s.push(right);
		s.push(left);
		while(!s.empty())
		{
			int _left = s.top();
			s.pop();
			int _right = s.top();
			int boundary = PartionSort1(a, _left, _right);
			s.pop();
			if (_left < boundary - 1)
			{
				s.push(boundary - 1);
				s.push(_left);
			}
			if (boundary + 1 < _right)
			{
				s.push(_right);
				s.push(boundary + 1);
			}
		}

	}
	else
	{
		return;
	}
}
void QuckSort(int *a,int left,int right)//快速排序
{
	
	if (left < right)
	{
		int boundary = PartionSort1(a, left, right);//调用了优化后的部分排序
		QuckSort(a, left, boundary-1);//这里一定要是boundary-1,否则会出现死循环
		QuckSort(a, boundary + 1, right);
	}
	
}

void MergeSection(int *a, int*tmp, int begin1, int end1, int begin2, int end2)
{
	int index = begin1;//这不能是0
	while (begin1 <= end1&&begin2 <= end2)
	{
		if(a[begin1] < a[begin2])
		{
			tmp[index++] = a[begin1++];
		}
		else
		{
			tmp[index++] = a[begin2++];
		}

	}
		while (begin1 <=end1)
		{
			tmp[index++] = a[begin1++];
		}
		while (begin2 <= end2)
		{
			tmp[index++] = a[begin2++];
		}

}
void _MergeSort(int *a,int *tmp ,int left, int right)
{
	if (left < right)
	{
		int boundary = left + (right - left) / 2;
		_MergeSort(a, tmp, left, boundary);
		_MergeSort(a, tmp, boundary + 1, right);
		MergeSection(a, tmp, left, boundary, boundary + 1, right);
		memcpy(a + left, tmp + left, (right - left + 1)*sizeof(int));//right-left+1
	}
}
void MergeSort(int *a, int size)//归并排序
{
	int left = 0;
	int right = size - 1;
	int* tmp = new int[size];
	_MergeSort(a,tmp, left, right);
	delete[] tmp;
}
void Print(int *a,int size)
{
	for (int i = 0; i <= size; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl; 
}
void CountSort(int *a, size_t size)//计数排序,思想是将对应元素作为辅助矩阵的下标,在辅助矩阵中计算它的个数
{
	assert(a);             //然后再将它拷回原来的矩阵中去
	int Max = a[0];
	int Min = a[0];
	for (size_t i = 1; i < size; ++i)
	{
		if (a[i]>Max)
		{
			Max = a[i];
		}

		else if (a[i] < Min)
		{
			Min = a[i];
		}
	}
	int range = Max - Min + 1;
	int *CountArray = new int[range];
	memset(CountArray, 0, sizeof(int)*range);
	for (size_t i = 0; i < size; i++)
	{
		CountArray[a[i] - Min]++;//有一个相对的偏移量,这样最小值将存在0的位置
	}
	size_t index = 0;
	for (size_t i = 0; i < range; ++i)
	{
		while (CountArray[i]-->0)
		{
			a[index++] = Min + i;
		}
	}
	delete[] CountArray;
}
int GetMaxDigit(int *a, size_t size)
{
	int digit = 1;//默认值为一位
	int Max = 10;
	for (size_t i = 0; i < size; i++)
	{
		while (a[i] >= Max)
		{
			++digit;
			Max *= 10;
		}
	}
	return digit;
}
void DigitSortLSD(int *a, size_t size)
{
	assert(a);
	int MaxDigit = GetMaxDigit(a, size);
	int *bucket = new int[size];
	int count[10];
	int start[10];
	int digit = 1;
	int bit = 1; 
	while (digit <= MaxDigit)
	{
		memset(count, 0, sizeof(int)* 10);
		memset(start, 0, sizeof(int)* 10);
		for (size_t i = 0; i < size; ++i)//统计0-9号桶有多少数字
		{
			int num = (a[i]) % 10;
			count[num]++;
		}
		start[0] = 0;
		for (size_t i = 0; i < size; ++i)
		{
			start[i] = start[i - 1] + count[i - 1];//当前桶的起始位置为前一个桶的起始位置
			//加上前一个桶的计数个数;
		}
		for (size_t i = 0; i < size; ++i)
		{
			int num = (a[i] / bit) % 10;
			bucket[start[num]] = a[i];
		}
		memcpy(a, bucket, sizeof(int)* 10);
		bit = bit * 10;
		++digit;
	}
}
int main()
{
	int  a[10] = { 1, 45, 23, 21, 48, 34, 33, 23, 40, 30 };
	Print(a, 9);
	//QuckSort2(a, 0, 9);
	//MergeSort(a, 10);
	//CountSort(a, 10);
	DigitSortLSD(a, 10);
	Print(a, 9);
}


你可能感兴趣的:(希尔排序,归并排序,快速排序,堆排序,直接插入排序)