排序算法(C++代码)

参考文章

https://blog.csdn.net/opooc/article/details/80994353

https://blog.csdn.net/qq_37941471/article/details/80710099

https://www.cnblogs.com/zyb428/p/5673738.html

一、冒泡排序

思想:重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

特性:交换排序; 时间A:N^2 , B:N^2 , E:N; 空间1; 稳定。

void BubbleSort(int data[], int size) {
	for (int i = 1; i < size; i++) {
		bool sorted = true;
		for (int j = 0; j < size - i; j++) {
			if (data[j] > data[j + 1]) {
				swap(data[j], data[j + 1]);  //#include <utility>
				sorted = false;
			}
		}
		if (sorted)
			break;
	}
}

二、快速排序

思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

特性:交换排序,时间A:N logN,W:N logN,B:N logN,空间:logN,不稳定。

int OnceQuickSort(int data[], int left, int right) {
	int key = data[right];

	//left和right是下一个要填的位置
	while (left < right) {
		//从左边找大于等于pivot的数
		while (left < right && data[left] < key)
			left++;
		if (left < right)
			data[right--] = data[left];
                //从右边找小于pivot的数
		while (left < right && data[right] >= key)
			right--;
		if (left < right)
			data[left++] = data[right];
	}

	data[left] = key;
	return left;
}
void QuickSort(int data[], int left, int right) {
	if (left < right) {
		srand(time(NULL));  //#include <ctime>
		int ranPos = left + rand() % (right - left + 1);  //#include <cstdlib>
		swap(data[ranPos], data[right]);  //#include <utility>
		int pivot = OnceQuickSort(data, left, right);
		QuickSort(data, left, pivot - 1);
		QuickSort(data, pivot + 1, right);
	}
}

三、插入排序

思想:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

特性:插入排序,时间A:N^2,W:N^2,B:N,空间:1,稳定

void InsertSort(int data[], int size) {
	for (int i = 1; i < size; i++) {
		int key = data[i], prePos;
		for (prePos = i - 1; prePos >= 0 && data[j] > key; prePos--) {
			data[prePos + 1] = data[prePos];
			
		}
		data[prePos + 1] = key;
	}
}

四、希尔排序

思想:缩小增量。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时(用gap = gap/3+1 控制,一般gap不要超过数组大小的一半),保证了最后一次进行直接插入排序,算法终止。(其中直接插入排序是希尔排序gap=1的特例)另外,gap越大,值越大的容易到最后面,但是不太接近有序。

特性:插入排序;时间A:N^1.3 , B:N^2 , E:N;空间1;不稳定。

void ShellSort(int data[], int size) {
	int gap = size;
	//1. gap > 1 预排序
	//2. gap == 1 直接插入排序
	//3. gap = gap/3 + 1; 保证最后一次排序是直接插入排序

	while (gap > 1) {
		gap = gap / 3 + 1;

		for (int i = 0; i < size - gap; i++) {
			int  key = data[i + gap], prePos = i;
			while (prePos >= 0 && data[prePos] > key) {
				data[prePos + gap] = data[prePos];
				prePos = prePos - gap;
			}
			data[prePos + gap] = key;
		}
	}
}

五、选择排序

思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

特性:选择排序;时间A:N^2 , B:N^2 , E:N^2 ; 空间1;稳定

void SelectSort(int data[], int size) {
	for (int i = 0; i < size - 1; i ++) {
		int minPos = i;
		for (int j = i + 1; j < size; j ++) {
			if (data[j] < data[minPos])
				minPos = j;
		}
		swap(data[i], data[minPos]);  //#include <utility>
	}
}

六、堆排序

思想:堆排序过程将待排序的序列构造成一个堆,选出堆中最大的移走,再把剩余的元素调整成堆,找出最大的再移走,重复直至有序。升序建大堆,降序建小堆。

特性:选择排序;时间A:N logN,B:N logN,E:N logN;空间1;不稳定。

void HeapSort(int data[], int size) {
	//从最后一个父节点开始,建大堆
	for (int i = size / 2 - 1; i >= 0; --i) {
		Heapify(data, i, size);
	}
	//从堆中的取出最大的元素data[0]放到数组末尾,再调整堆
	for (int i = size - 1; i > 0; --i) {
		swap(data[0], data[i]);
		int temp = data[i];
		Heapify(data, 0, i);
	}
}
void Heapify(int data[], int root, int n) {
	int parent = root;
	int child = parent * 2 + 1;  //左孩子

	while (child < n) {
		//找出较大的孩子,再和父亲比
		if (child + 1 < n && data[child + 1] > data[child])
			child ++;

		//左子树和右子树已经是堆
		if (data[parent] < data[child]) {
			swap(data[parent], data[child]);
			parent = child;
			child = parent * 2 + 1;
			//交换父亲和较大孩子之后,只需要将原本较大孩子的子树调整成堆
		}
		else
			break;
	}
}

七、归并排序

思想:分治。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

特性:插入排序;时间A:N logN,B:N logN,E:N logN;空间N;稳定。

void MergeSort(int data[], int left, int right) {
	if (left < right) {
		int mid = (left + right) / 2;
		MergeSort(data, left, mid);
		MergeSort(data, mid + 1, right);

		Merge(data, left, mid, right);
	}
}
void Merge(int data[], int left, int mid, int right) {
	int size = right - left + 1;
	int* merged = new int[size];
	int p1 = left, p2 = mid + 1, p3 = 0;

	while (p1 <= mid && p2 <= right) {
		merged[p3++] = data[p1] >= data[p2] ? data[p1++] : data[p2++];
	}
	while (p1 <= mid) {
		merged[p3++] = data[p1++];
	}
	while (p2 <= right) {
		merged[p3++] = data[p2++];
	}

	for (int i = 0; i < size; i++) {
		data[left + i] = merged[i];
	}
}

 

测试题

在以下排序算法中,关键字比较的次数与记录的初始排列次序无关的是()。
A. 希尔排序
B. 冒泡排序
C. 插入排序
D. 直接选择排序

解析:选择排序每次都需要遍历剩下的序列 找出最大或最小值进行与当前位置的交换 无论什么情况下时间复杂度都为O(N2) **
答案:D

待排序元素规模较小时,宜选取哪种排序算法效率最高( )
A. 堆排序
B. 归并排序
C. 冒泡排序
D. 希尔排序

解析:递归时间可能长于比较时间
答案:C

适合并行处理的排序算法是()
A. 选择排序
B. 快速排序
C. 希尔排序
D. 基数排序

解析:基数排序:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。可以同时操作多个元素,从而实现了并行处理。
答案:D

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值