七大排序算法(C++)

七大排序算法(C++)

1.快速排序

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

1、首先设定一个分界值,通过该分界值将数组分成左右两部分。

2、将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。 

3、然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

代码实现

int part(vector<int> &arr, int left, int right)//找到基准元素的位置(循环一次基准元素的位置就是他最终的位置)
{
	int keyi = left;
	while (left < right)   //这里的left < right是判断下一次循环是否进行
	{            //这里的left < right是限制不能找过界
		while (left < right&&arr[keyi] <= arr[right])//右边找小
		{
			right--;
		}
		while (left < right && arr[keyi] >= arr[left])//左边找大
		{
			left++;
		}
		swap(arr[right], arr[left]);
	}
	swap(arr[left], arr[keyi]);

	return left;
}

void Quicksort(vector<int> &arr,int begin,int end)
{

	if (begin >= end)//该区间只有一个数了或者该区间不存在
	{
		return;
	}
	int pivotPos = part(arr, begin, end);

	Quicksort(arr, begin, pivotPos - 1);//递归左区间

	Quicksort(arr, pivotPos + 1, end);//递归右区间

}

2.插入排序

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

代码实现

void insterSort(vector<int> &arr,int n)
{
	//把[0,end]当成是有序的 插入tmp依旧有序
	for (int i = 1; i < n; i++)
	{
		int end = i-1;
		int tmp = arr[i];

		while (end >= 0)
		{
			if (arr[end] > tmp)//如果要插入的数比前面有序数组最大数的小
			{
				arr[end + 1]=arr[end]; //把有序数组最后一位往后挪一位(就是tmp原来的位置)
				--end;
			}
			else
			{
				break;
			}
		}
		arr[end+1] = tmp;
	}
}

3.希尔排序

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

代码实现

void shellSort(vector<int>& arr,int n)  //希尔排序
{
	// 定义间隔序列,通常选择的间隔序列为 h = n / 2, h = h / 2, ...
	for (int gap = n / 2; gap > 0; gap /= 2)
	{
		// 对每个子序列进行插入排序
		for (int i = gap; i < n; i++) 
		{
			int temp = arr[i];
			int j;

			// 在子序列中执行插入排序
			for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) 
			{
				arr[j] = arr[j - gap];
			}

			arr[j] = temp;
		}
	}
}


 4.冒泡排序

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

代码实现

void bubbleSort(vector<int> &arr, int n)
{
	bool swapped;
	for (int i = 0; i < n - 1; i++)
	{
		swapped = false;
		for (int j = 0; j < n - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				swap(arr[j], arr[j + 1]);
				swapped = true;
			}
		}
		if (!swapped)
		{
			break;
		}
	}
}

5.选择排序

它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

代码实现

void SelectSort(vector<int> &arr, int n)//选择排序
{
	for (int i = 0; i < n - 1; i++)
	{
		int minIndex = i;
		for (int j = i + 1; j < n ; j++)
		{
			if (arr[j] < arr[minIndex])
			{
				minIndex = j;
			}
		}
		swap(arr[minIndex],arr[i]);

	}
}

6.堆排序

在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:

1.最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点

2.创建最大堆(Build Max Heap):将堆中的所有数据重新排序

3.堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算 

代码实现

void AdJustUp(vector<int> &arr, int child)//建堆——向上调整
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] > arr[parent])
		{
			swap(arr[child], arr[parent]);

			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void AdJustDown(vector<int> &arr,int n,int parent)
{
	int child = parent * 2 + 1;//左孩子
	while (child < n )//当后面没有孩子的时候就返回
	{
		if (child+1<n&&arr[child]<arr[child+1])//找出左右孩子中小/大的一个(右孩子存在并且比左孩子大/小)
		{
			child++;
		}

		if (arr[child] > arr[parent])
		{
			swap(arr[child], arr[parent]);

			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(vector<int> &arr, int n)//堆排序
{
	//建堆——向上调整(小堆)
	for (int i = 1; i < n ; i++)
	{
		AdJustUp(arr, i);
	}

	int end=n-1;
	while (end > 0)
	{
		swap(arr[0], arr[end]);
		//再调整选出次小的数
		AdJustDown(arr,end,0);
		end--;
	}

}

7.归并排序

归并操作的工作原理如下:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针超出序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

代码实现

void Merge(vector<int> &arr,vector<int> &arr1,int begin,int mid,int end)
{
	int i = begin, j = mid + 1, k = end;
	//i、j 分别标记第一和第二个数列的当前位置,k 是标记当前要放到整体的哪一个位置
	while (i <= mid && j <= end)    //如果两个数列的数都没放完,循环
	{
		if (arr[i] < arr[j])
			arr1[k++] = arr1[i++];
		else
			arr1[k++] = arr[j++];   //将a[i] 和 a[j] 中小的那个放入 b[k],然后将相应的标记变量增加
	}        // b[k++]=a[i++] 和 b[k++]=a[j++] 是先赋值,再增加
	while (i <= mid)
		arr1[k++] = arr[i++];
	while (j <= end)
		arr1[k++] = arr[j++];    //当有一个数列放完了,就将另一个数列剩下的数按顺序放好
	for (int i = begin; i <= end; i++)
		arr[i] = arr1[i];                //将 b 数组里的东西放入 a 数组,因为 b 数组还可能要继续使用
}
void MergeSort(vector<int>& arr, int begin, int end)//归并排序
{
	vector<int> arr1;
	if (begin >= end)//如果开头 ≥ 结尾,那么就说明数列分完了,就要返回
	{
		return;
	}
	
	int mid = (begin + end) / 2; //将中间数求出来,用中间数把数列分成两段
	MergeSort(arr,begin, mid);//左区间
	MergeSort(arr,mid + 1, end);//右区间     //递归,继续分离
	Merge(arr,arr1,begin, mid, end);        //分离玩之后就合并
}

排序算法复杂度及稳定性分析

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值