十大排序算法--C++实现(上)

十大排序算法

选择排序

1. 方法

        从第0个元素往后遍历,针对每一个当前元素,往后找到最小的一个元素,然后与当前元素交换位置。(即为每个位置选择正确的元素)

2. 步骤

  1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  2. 从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾
  3. 以此类推,直到所有元素均排序完毕

3. 动图演示

4. 代码实现

void SelectSort(vector<int>& arr) {
	int n = arr.size();
	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;
			}
		}
		int tmp = arr[minIndex];
		arr[minIndex] = arr[i];
		arr[i] = tmp;
	}
}

 

插入排序

1. 方法:

       从第1个元素开始往后遍历,如果当前元素比它前面的元素小,则向前插入。

2. 步骤:

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

3. 动图演示:

4. 代码实现

void InsertSort(vector<int>& arr) {
	int n = arr.size();
	for (int i = 1; i < n; i++) {
		int current = arr[i];  //当前元素
		int pre = i - 1;      //前一个元素
		while (pre >= 0 && arr[pre] > current) {//如果前一个元素比当前元素大,则后移
			arr[pre+1] = arr[pre];
			pre--;
		}
		arr[pre + 1] = current;
	}
}

 

希尔排序

1. 方法

       简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。即按增量将数组分组,然后对每组进行插入排序。逐渐将增量递减,递减到1时则排序完毕。

2. 步骤

  • 初始增量gap=length/2=5,意味着整个数组被分为5组,对这5组分别进行插入排序
  • 缩小增量gap=5/2=2,数组被分为2组,对这两组再进行插入排序
  • 再缩小增量2/2=1,于是整个数组为1组,再进行插入排序得有序数组

3. 动图演示

4. 代码示例

void ShellSort(vector<int>& arr) {
	int n = arr.size();
	//对每组间隔为gap的分组进行排序,开始为gap=n/2;
	for (int gap = n / 2; gap > 0; gap / 2) {
		//对各个局部分组进行插入排序
		for (int i = gap; i < n; i++) {
			int curr = arr[i];
			int prev = i - gap;
			while (prev >= 0 && curr < arr[prev]) {
				arr[prev + gap] = arr[prev];
				prev -= gap;
			}
			arr[prev + gap] = curr;
		}
	}
}

 

冒泡排序

1. 方法:

        通过不断改善局部的有序性实现整体的有序:从前向后依次检查每一对相邻元素,一旦发现逆序即交换二者的位置。对于长度为n的序列,共需做n - 1次比较和不超过n - 1次交换,这一过程称作一趟扫描交换。每一趟扫描交换下来之后,排在最右的元素就会是最大的数。

2. 步骤

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

4. 程序示例:

//未优化版本
void BubbleSort(vector<int>& arr) {
	int n = arr.size();
	for (int i = 0; i < n - 1; i++) {
		for (int j =0; j < n - i - 1; j++) {
			if (arr[j] > arr[j + 1]) {
				int tmp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = tmp;
			}
		}
	}
}
//优化版本​
void bubblesort1A(int A[], int n) { //冒泡排序算法
    bool sorted = false; //整体排序标志,首先假定尚未排序
    while (!sorted) { //在尚未确认已全局排序之前,逐趟进行扫描交换
        sorted = true; //假定已经排序
        for (int i = 1; i < n; i++) { //自左向右逐对检查弼前范围A[0, n)内癿各相邻元素
            if (A[i - 1] > A[i]) { //一旦A[i - 1]与A[i]逆序,则
                swap(A[i - 1], A[i]); //交换
                sorted = false; //因整体排序不能保证,需要清除排序标志
            } 
        }
        n--; //至此末元素必然就位,故可以缩短待排序序列的有效长度
    }
} //借助布尔型标志位sorted,可及时提前退出,而不致总是蛮力地做n - 1趟扫描交换

 

归并排序

1. 方法

        归并属于分治法,第一步把数组分成左右两份,分别对左边和右边进行排序(递归), 最后把已经排序好的左边和右边合并到结果里。

2. 步骤

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

3. 动图演示: 

4. 程序代码 

void Merge(vector<int>& arr, int lo, int mi, int hi) {
	vector<int> res;
	int i = lo, j = mi+1;
	while (i <= mi && j <= hi) {
		if (arr[i] < arr[j]) {
			res.push_back(arr[i++]);
		}
		else {
			res.push_back(arr[j++]);
		}
	}
	while (i <= mi)  res.push_back(arr[i++]);
	while (j <= hi)  res.push_back(arr[j++]);
	//放回原数组
	for ( int i = 0; i < res.size(); i++) {
		arr[lo+i] = res[i];
	}
}
void MergeSort(vector<int>& arr, int left, int right) {
	if (left >= right) { // 如果只有一个元素,则不用继续排,直接返回
		return;
	}
	int mid = left + (right - left) / 2;
	MergeSort(arr, left, mid);
	MergeSort(arr, mid+1, right);
	Merge(arr, left, mid, right);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值