比较排序总结——直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序

一,直接插入排序

插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

步骤:

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置中
  6. 重复步骤2
代码实现:

void Insertsort(int *a,size_t n)
{
assert(a);
for (int i = 1; i < n; i++)
{
int index = i;
int tmp = a[index];
int prev = index - 1;
while (prev >= 0 && a[prev] > tmp)
{
a[prev + 1] = a[prev];
prev--;
}
a[prev+ 1] = tmp;
}
}
void Count_test()
{
int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
cout << "排序前:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
Insertsort(a, 10);
cout << "排序后:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
}

二,希尔排序

希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1、插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率

2、但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

代码实现:

void Shellsort(int *a, size_t n)
{
assert(a);
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (size_t i = gap; i < n; i++)
{
int index = i;
int tmp = a[index];
int prev = index - gap;
while (prev >= 0 && a[prev] > tmp)
{
a[prev + gap] = a[prev];
prev -= gap;
}
a[prev + gap] = tmp;
}
}
}
void Count_test()
{
int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
cout << "排序前:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
Shellsort(a, 10);
cout << "排序后:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
}

三,选择排序

它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

                          

代码实现:

选择排序
void Selectsort(int *a, size_t n)
{
assert(a);
int index = 0;
for (int i = 0; i < n-1; i++)
{
index = i;
for (int j = i+1; j < n; j++)
{
if (a[j] < a[index])
{
index=j;
}
}
if (index != i)
{
swap(a[i], a[index]);
}
}
}
void Selectest()
{
int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
cout << "排序前:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
Selectsort(a, 10);
cout << "排序后:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
}

四,堆排序

堆排序是一种选择排序。建立的初始堆为初始的无序区。

排序开始,首先输出堆顶元素(因为它是最值),将堆顶元素和最后一个元素交换,这样,第n个位置(即最后一个位置)作为有序区,前n-1个位置仍是无序区,对无序区进行调整,得到堆之后,再交换堆顶和最后一个元素,这样有序区长度变为2。。。

  不断进行此操作,将剩下的元素重新调整为堆,然后输出堆顶元素到有序区。每次交换都导致无序区-1,有序区+1。不断重复此过程直到有序区长度增长为n-1,排序完成。

堆存储:




图解:




代码实现:

void adjust(int *a, size_t n, int root)
{
int parent = root;
int child = parent * 2 + 1;
while (child < n)
{
if ((child + 1 < n) && (a[child] < a[child + 1]))//保证右边大于左边
{
child++;
}
if (a[child] > a[parent])
{
swap(a[child], a[parent]);
parent = child;
child = child * 2 + 1;
}
else
{
break;
}
}
}
void Heapsort(int *a, size_t n)//小堆
{
assert(a);
for (int i = (n - 2) / 2; i >= 0; i--)//i从最后一个叶节点的父节点开始
{
adjust(a, n, i);
}
for (int j = n - 1; j >= 0; j--)
{
swap(a[0], a[j]);
adjust(a, j, 0);
}
}
void Heaptest()
{
int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
cout << "排序前:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
Heapsort(a, 10);
cout << "排序后:" << endl;
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
}


五,排序

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码实现:

void Bubblesort(int *a,size_t n)
{
	assert(a);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n - 1 - i; j++)
		{
			if (a[j]>a[j + 1])
				swap(a[j], a[j + 1]);
		}
	}
}
void Bubbletest()
{
	int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
	cout << "排序前:" << endl;
	for (int i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
	Bubblesort(a, 10);
	cout << "排序后:" << endl;
	for (int i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
}

六,快速 排序

  1. 从数列中挑出一个元素,称为 “基准”(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
#include<stack>
int partsort1(int *a, int left, int right)//不优化
{
	int key = a[right];
	int begin = left;
	int end = right - 1;
	while (begin<end)
	{
		while (begin < end&&a[begin] <= key)
		{
			begin++;
		}
		while (begin < end&&a[end] >= key)
		{
			end--;
		}
		if (a[begin] > a[end])
		{
			swap(a[begin], a[end]);
		}
	}
	if (a[begin] > key)
	{
		swap(a[begin], a[right]);
		return begin;
	}
	else
	{
		return right;
	}
}
int partsort2(int *a, int left, int right)//优化
{
	assert(a);
	int key = a[right];
	int cur = left;
	int prev = cur - 1;
	while (cur < right)
	{
		if (a[cur] < key && ++prev != cur)
		{
			swap(a[cur], a[prev]);
		}
		++cur;
	}
	swap(a[++prev], a[right]);
	return prev;
}
void Quicksort1(int *a, int left, int right)//递归
{
	assert(a);
	if (left < right)
	{
		int div = partsort1(a, left, right);
		Quicksort1(a, left, div-1);
		Quicksort1(a, div+1, right);
	}
}
void Quicksort2(int *a, int left, int right)//非递归
{
	assert(a);
	stack<int> s;
	if (right > left)
	{
		int div = partsort2(a, left, right);
		if (left < div - 1)
		{
			s.push(left);
			s.push(div - 1);
		}
		if (right > div + 1)
		{
			s.push(div + 1);
			s.push(right);
		}

		while (!s.empty())
		{
			int end = s.top();
			s.pop();
			int begin = s.top();
			s.pop();
			div = partsort2(a, begin, end);
			if (begin < div - 1)
			{
				s.push(begin);
				s.push(div - 1);
			}
			if (div + 1 < end)
			{
				s.push(div + 1);
				s.push(end);
			}
		}
	}
}
void Quicktest()
{
	int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
	cout << "排序前:" << endl;
	for (int i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
	//Quicksort1(a, 0, 9);
	Quicksort2(a, 0, 9);
	cout << "排序后:" << endl;
	for (int i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
}
七,归并 排序

归并排序,它采取分而治之(Divide-and-Conquer)的策略,时间复杂度是Θ(nlgn)。归并排序的步骤如下:

1. Divide: 把长度为n的输入序列分成两个长度为n/2的子序列。

2. Conquer: 对这两个子序列分别采用归并排序。

3. Combine: 将两个排序好的子序列合并成一个最终的排序序列。

void SectionSort(int *a, int *tmp, int begin1, int end1, int begin2, int end2)
{
	int index = begin1;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[index++] = a[begin1++];
		}
		else
		{
			tmp[index++] = a[begin2++];
		}
	}
	if (begin1 <= end1)
	{
		for (int i = begin1; i <= end1; i++)
		{
			tmp[index++] = a[begin1++];
		}
	}
	if (begin2 <= end2)
	{
		for (int i = begin2; i <= end2; i++)
		{
			tmp[index++] = a[begin2++];
		}
	}
}

void _MergeSort(int *a, int *tmp, int left, int right)
{
	int mid = left + (right - left) / 2;
	if (left < right)
	{
		_MergeSort(a, tmp, left, mid);
		_MergeSort(a, tmp, mid + 1, right);
		SectionSort(a, tmp, left, mid, mid + 1, right);
		memcpy(a + left, tmp + left, (right - left + 1)*sizeof(int));
	}
}
void MergeSort(int *a, int size, int left, int right)
{
	int *tmp = new int[size];
	_MergeSort(a, tmp, left, right);
	delete[]tmp;
}
void Mergetest()
{
	int a[10] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
	cout << "排序前:" << endl;
	for (int i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
	MergeSort(a, 10, 0, 9);
	cout << "排序后:" << endl;
	for (int i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值