各种排序算法C++(快排、归并、堆排序、冒泡、选择、插入)

这或许是东半球分析十大排序算法最好的一篇文章
十大经典排序算法动画与解析,看我就够了!
临时用的Dev,用到的函数必须先写在前面。

知乎这个写的不错

轻松搞定十大排序算法|C++版(上)
轻松搞定十大排序算法|C++版(下)

快排 QuickSort

思想:,先找到中间那个数pivot,,将大于pivot的放右边,将小于pivot的放左边,每次搞定一个数!(中间的一个数)。此时两边的数并不是有序的。

区别:归并排序是分两块,两块都排好序之后,再将两边排好序的数合再并成一个排序的序列。

1.选定pivot中心轴;
2.将大于pivot的数字放在pivot的右边;
3.将小于pivot的数字放在pivot的左边;
4.分别对左右子序列重复前三步操作。
#include
using namespace std;
int partition(int* arr,int left,int right){
	int pivot=arr[left];  //注意
	while(left<right){  //注意
		while(arr[right]>=pivot && left<right) right--;
		arr[left]=arr[right];//这覆盖可以,写swap函数交换也可以,道理是一样的
		while(arr[left]<=pivot && left<right) left++;
		arr[right]=arr[left];
	}
	arr[left]=pivot;
	return left;
}
//快速排序
void quick_sort(int* arr, int left,int right){
	if(left<right){  //注意
		int index=partition(arr,left,right);
		quick_sort(arr,left,index-1);
		quick_sort(arr,index+1,right);
	}
}

int main(){
	int arr[]={1,1,5,8,3,7,4,1,1};
	int size=sizeof(arr)/sizeof(arr[0]); //计算数组大小
	quick_sort(arr,0,size-1);  //确切下标
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

/*交换函数
void swap(int* arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
*/
/* 左神的partition函数用从C++改的能跑通
int partition(int* arr, int l, int r) {
		int less = l - 1;
		int more = r;
		while (l < more) {
			if (arr[l] < arr[r]) {
				swap(arr, ++less, l++);
			} else if (arr[l] > arr[r]) {
				swap(arr, --more, l);
			} else {
				l++;
			}
		}
		swap(arr, more, r);
		int w[2]={less + 1, more};
		return w;
	}
*/

归并排序 MergeSort

各种排序算法C++(快排、归并、堆排序、冒泡、选择、插入)_第1张图片

我们将本是无序的数组序列,通过两两合并排序之后再合并,最终获得一个有序的数组。

需要辅助数组

左边排好,右边排好,再两边合并排好。

#include
using namespace std;

void merge(int* arr, int l, int m, int r) {//这个函数比快排多个参数,m
	int* help = new int[r - l + 1];  //注意新建数组只能只能这样建 int*
	int i = 0;
	int p1 = l;//指向左侧部分第一个数
	int p2 = m + 1;//指向右侧部分第一个数
	while (p1 <= m && p2 <= r) { //谁小填谁,相当于个排序
		help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
	}
	while (p1 <= m) {  //把剩下的追加到后面,如果p1没越界,p2必越界。
		help[i++] = arr[p1++];
	}
	while (p2 <= r) {
		help[i++] = arr[p2++];
	}
	for (i = 0; i < (r-l+1); i++) {
		arr[l + i] = help[i];  //注意l+i //把help里的数复制到原数组arr
	}
}
//归并排序 
void mergeSort(int* arr, int l, int r) {
	if (l == r) {//注意这个条件   //只有一个数时
		return;
	}
	int mid = l + ((r - l) >> 1);  // (l+r)/2
	mergeSort(arr, l, mid);  //左部分排好
	mergeSort(arr, mid + 1, r);//右部分排好
	merge(arr, l, mid, r); //再合并排序
}

int main(){
	int arr[]={9,1,5,8,3,7,4,1,1,2};
	int size=sizeof(arr)/sizeof(arr[0]);
	mergeSort(arr, 0, size-1);
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

原来的左神的,多了一段。暂时不用。

#include
using namespace std;

void swap(int* arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
//归并排序 
void merge(int* arr, int l, int m, int r) {
	int* help = new int[r - l + 1];  //辅助数组
	int i = 0;
	int p1 = l;//指向左侧部分第一个数
	int p2 = m + 1;//指向右侧部分第一个数
	while (p1 <= m && p2 <= r) { //谁小填谁
		help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
	}
	while (p1 <= m) {  //如果p1没越界,p2必越界
		help[i++] = arr[p1++];
	}
	while (p2 <= r) {
		help[i++] = arr[p2++];
	}
	for (i = 0; i < (r-l+1); i++) {
		arr[l + i] = help[i];   //把help里的数复制到原数组arr
	}
}
void mergeSort(int* arr, int l, int r) {
	if (l == r) {//只有一个数
		return;
	}
	int mid = l + ((r - l) >> 1);  // (l+r)/2
	mergeSort(arr, l, mid);  //左部分排好
	mergeSort(arr, mid + 1, r);//右部分排好
	merge(arr, l, mid, r);
}

//归并排序 
void mergeSort(int* arr, int length) {
	if (arr == NULL || length < 2) {
		return;
	}
	mergeSort(arr,0,length - 1);
}

int main(){
	int arr[]={9,1,5,8,3,7,4,1,1,2};
	int size=sizeof(arr)/sizeof(arr[0]);
	mergeSort(arr,size);
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

堆排序 HeapSort

介绍大顶堆、小顶堆

堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

注意红框内容:
各种排序算法C++(快排、归并、堆排序、冒泡、选择、插入)_第2张图片
各种排序算法C++(快排、归并、堆排序、冒泡、选择、插入)_第3张图片

思路:

那个二叉树只是为计算而想象成的一颗二叉树。

1.让一个数组变成大根堆(并不是有序),第一步就把大顶推建立好,
建立好的大顶推像上图一样。
2.建立好大根堆之后,堆顶位置为整个数组最大值,让它和最后位置交换,,
换完之后,最大值来到了数组最后位置;
3.此时,最后位置为最大值,不动了,让堆大小减一;剩下的做heapify处理
4.每次搞定一个末尾的值
#include
using namespace std;

void swap(int* arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
//向上走。
//第一步先整体建立起一个大顶推,后面才好说。。建立大根堆过程(无序的)
void heapInsert(int* arr, int index) {
	while (arr[index] > arr[(index - 1) / 2]) {//如果比当前父节点位置大,就和父位置交换
		swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;// index往上跑,一直往上跑
	}
}
//向下走。
//其中有一个值变小,往下沉的过程,重新变成大根堆
//size为最右的边界,size是取不到的
void heapify(int* arr, int index, int size) {
	int left = index * 2 + 1;
	                     //下面2句的意思是找到三者之间最大的(根/左/右)
	while (left < size) { //注意while只判断left
		int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//选出左右孩子中较大的那个
		largest = arr[largest] > arr[index] ? largest : index;
		if (largest == index) {
			break;
		}
		swap(arr, largest, index);
		index = largest;
		left = index * 2 + 1;
	}
}

//堆排序 
void heapSort(int* arr, int size) {
	if (arr == NULL || size< 2) {
		return;
	}
	for (int i = 0; i < size; i++) {//建立大顶推的过程
		heapInsert(arr, i);//循环发生完之后,整个数组就变成大根堆了
	}
	swap(arr, 0, size-1);//建立好大根堆之后,堆顶位置为整个数组最大值,让它和最后位置交换,,换完之后,最大值来到了数组最后位置
	size--;
	while (size > 0) {
		heapify(arr, 0, size);
		swap(arr, 0, size-1);//循环操作上述过程
		size--;
	}
}

int main(){
	int arr[]={9,1,5,8,3,7,4,1,1,2};
	int size=sizeof(arr)/sizeof(arr[0]);
	heapSort(arr,size);
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

下面这个暂时不用。。之前 heapSort 函数的最后一点是这么写的,不好理解,所以换成了上面那种。其实是一样的,只不过浓缩了。

//堆排序 
void heapSort(int* arr, int length) {
	if (arr == NULL || length < 2) {
		return;
	}
	for (int i = 0; i < length; i++) {
		heapInsert(arr, i);//循环发生完之后,整个数组就变成大根堆了
	}
	int size = length;
	//我说的就是下面这点。。。
	swap(arr, 0, --size);//建立好大根堆之后,堆顶位置为整个数组最大值,让它和最后位置交换,,换完之后,最大值来到了数组最后位置
	while (size > 0) {
		heapify(arr, 0, size);
		swap(arr, 0, --size);//循环操作上述过程
	}
}

冒泡 BubbleSort

#include
using namespace std;
void swap(int* arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
//冒泡排序 
void bubbleSort(int* arr, int size){
	if (arr == NULL || size < 2) {
		return;
	}
	for (int e = size - 1; e > 0; e--) {//e先指向最后一个数
		for (int i = 0; i < e; i++) { //从0至倒数第二个数
			if (arr[i] > arr[i + 1]) {
				swap(arr, i, i + 1);
			}
		}
	}
}

int main(){
	int arr[]={9,1,5,8,3,7,4,1,1,2};
	int size=sizeof(arr)/sizeof(arr[0]);
	bubbleSort(arr,size);
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

冒泡优化版

如果发现在某一趟排序的过程中,数组已经排序了,此时不用再继续排序。
避免了因有序情况下的无意义循环判断。
各种排序算法C++(快排、归并、堆排序、冒泡、选择、插入)_第4张图片
比如在第三趟,发现已经有序了,并没有执行交换操作,所以flag为true,跳出循环。

//冒泡排序优化
void bubbleSort(int* arr, int size){
	if (arr == NULL || size < 2) {
		return;
	}
	for (int e = size - 1; e > 0; e--) { //有这么多趟 
		bool flag = true; //设置标记 
		for (int i = 0; i < e; i++) {//开始交换 
			if (arr[i] > arr[i + 1]) {
				swap(arr, i, i + 1);
				flag  =false;//如果有交换 ,就设为false,一旦没有交换,还是true不变 
			}
		}
		if(flag) break; 
	}
}

选择排序 SelectionSort

#include
using namespace std;
void swap(int* arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
//选择排序 
void selectionSort(int* arr, int length) {
		if (arr == NULL || length < 2) {
			return;
		}
		for (int i = 0; i < length - 1; i++) { //0~倒数第二个 
			int minIndex = i;
			for (int j = i + 1; j < length; j++) { //从i+1直到最后去选择一个最小的,然后交换
				minIndex = arr[j] < arr[minIndex] ? j : minIndex;
			}
			swap(arr, i, minIndex);
		}
	}
int main(){
	int arr[]={9,1,5,8,3,7,4,1,1,2};
	int size=sizeof(arr)/sizeof(arr[0]);
	selectionSort(arr,size);
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

插入排序 InsertionSort

将一个记录插入到已经排好序的有序序列中,从而得到一个新的、记录数增1的有序表。

#include
using namespace std;
void swap(int* arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
//插入排序 
void insertionSort(int* arr, int length) {
		if (arr == NULL || length < 2) {
			return;
		}
		for (int i = 1; i < length; i++) {//0位置不用管,从第1位置到最后一个位置都要去比较
			for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
				swap(arr, j, j + 1);
			}
		}
	}
int main(){
	int arr[]={9,1,5,8,3,7,4,1,1,2};
	int size=sizeof(arr)/sizeof(arr[0]);
	insertionSort(arr,size);
	for(int i=0;i<size;i++){
		//printf("%d",arr[i]);
		cout<<arr[i];
	}
	return 0;
}

左神(JAVA)

冒泡排序

package basic_class_01;
import java.util.Arrays;
public class Code_00_BubbleSort {

	public static void bubbleSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int e = arr.length - 1; e > 0; e--) {
			for (int i = 0; i < e; i++) {
				if (arr[i] > arr[i + 1]) {
					swap(arr, i, i + 1);
				}
			}
		}
	}

	public static void swap(int[] arr, int i, int j) {
		arr[i] = arr[i] ^ arr[j];
		arr[j] = arr[i] ^ arr[j];
		arr[i] = arr[i] ^ arr[j];
	}

	// for test
	public static void comparator(int[] arr) {
		Arrays.sort(arr);
	}

	// for test
	public static int[] generateRandomArray(int maxSize, int maxValue) {
		int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
		}
		return arr;
	}

	// for test
	public static int[] copyArray(int[] arr) {
		if (arr == null) {
			return null;
		}
		int[] res = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
			res[i] = arr[i];
		}
		return res;
	}

	// for test
	public static boolean isEqual(int[] arr1, int[] arr2) {
		if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
			return false;
		}
		if (arr1 == null && arr2 == null) {
			return true;
		}
		if (arr1.length != arr2.length) {
			return false;
		}
		for (int i = 0; i < arr1.length; i++) {
			if (arr1[i] != arr2[i]) {
				return false;
			}
		}
		return true;
	}

	// for test
	public static void printArray(int[] arr) {
		if (arr == null) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}
	// for test
	public static void main(String[] args) {
		int testTime = 500000;
		int maxSize = 100;
		int maxValue = 100;
		boolean succeed = true;
		for (int i = 0; i < testTime; i++) {
			int[] arr1 = generateRandomArray(maxSize, maxValue);
			int[] arr2 = copyArray(arr1);
			bubbleSort(arr1);
			comparator(arr2);
			if (!isEqual(arr1, arr2)) {
				succeed = false;
				break;
			}
		}
		System.out.println(succeed ? "Nice!" : "Fucking fucked!");

		int[] arr = generateRandomArray(maxSize, maxValue);
		printArray(arr);
		bubbleSort(arr);
		printArray(arr);
	}
}

简单选择排序

package basic_class_01;
import java.util.Arrays;
public class Code_02_SelectionSort {

	public static void selectionSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length - 1; i++) {
			int minIndex = i;
			for (int j = i + 1; j < arr.length; j++) {
				minIndex = arr[j] < arr[minIndex] ? j : minIndex;
			}
			swap(arr, i, minIndex);
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}
}

直接插入排序

package basic_class_01;
import java.util.Arrays;
public class Code_01_InsertionSort {

	public static void insertionSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 1; i < arr.length; i++) {//0位置不用管,从第1位置到最后一个位置都要去比较
			for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
				swap(arr, j, j + 1);
			}
		}
	}

	public static void swap(int[] arr, int i, int j) {
		arr[i] = arr[i] ^ arr[j];
		arr[j] = arr[i] ^ arr[j];
		arr[i] = arr[i] ^ arr[j];
	}
}

堆排序

package basic_class_01;
import java.util.Arrays;
public class Code_03_HeapSort {
1.让一个数组变成大根堆(并不是有序)
2.建立好大根堆之后,堆顶位置为整个数组最大值,让它和最后位置交换,,换完之后,最大值来到了数组最后位置;
3.此时,最后位置为最大值,不动了,让堆大小减一;剩下的做heapify处理
4.每次搞定一个末尾的值
	public static void heapSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			heapInsert(arr, i);//循环发生完之后,整个数组就变成大根堆了
		}
		int size = arr.length;
		swap(arr, 0, --size);//建立好大根堆之后,堆顶位置为整个数组最大值,让它和最后位置交换,,换完之后,最大值来到了数组最后位置
		while (size > 0) {
			heapify(arr, 0, size);
			swap(arr, 0, --size);//循环操作上述过程
		}
	}
	//建立大根堆过程(无序的)
	public static void heapInsert(int[] arr, int index) {
		while (arr[index] > arr[(index - 1) / 2]) {//如果比当前父节点位置大,就和父位置交换
			swap(arr, index, (index - 1) / 2);
			index = (index - 1) / 2;// index往上跑
		}
	}
    //其中有一个值变小,往下沉的过程,重新变成大根堆
	public static void heapify(int[] arr, int index, int size) {
		int left = index * 2 + 1;
		while (left < size) {
			int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//选出左右孩子中较大的那个
			largest = arr[largest] > arr[index] ? largest : index;
			if (largest == index) {
				break;
			}
			swap(arr, largest, index);
			index = largest;
			left = index * 2 + 1;
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}
}

归并排序

package basic_class_01;

import java.util.Arrays;

public class Code_05_MergeSort {

	public static void mergeSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		mergeSort(arr, 0, arr.length - 1);
	}

	public static void mergeSort(int[] arr, int l, int r) {
		if (l == r) {//只有一个数
			return;
		}
		int mid = l + ((r - l) >> 1);  // (l+r)/2
		mergeSort(arr, l, mid);  //左部分排好
		mergeSort(arr, mid + 1, r);//右部分排好
		merge(arr, l, mid, r);
	}

	public static void merge(int[] arr, int l, int m, int r) {
		int[] help = new int[r - l + 1];  //辅助数组
		int i = 0;
		int p1 = l;//指向左侧部分第一个数
		int p2 = m + 1;//指向右侧部分第一个数
		while (p1 <= m && p2 <= r) { //谁小填谁
			help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
		}
		while (p1 <= m) {  //如果p1没越界,p2必越界
			help[i++] = arr[p1++];
		}
		while (p2 <= r) {
			help[i++] = arr[p2++];
		}
		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];   //把help里的数复制到原数组arr
		}
	}
}

快速排序

package basic_class_01;
import java.util.Arrays;
public class Code_04_QuickSort {

	public static void quickSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		quickSort(arr, 0, arr.length - 1);
	}

	public static void quickSort(int[] arr, int l, int r) {
		if (l < r) {
			//swap(arr, l + (int) (Math.random() * (r - l + 1)), r);  //随机快排
			int[] p = partition(arr, l, r);
			quickSort(arr, l, p[0] - 1);
			quickSort(arr, p[1] + 1, r);
		}
	}

	public static int[] partition(int[] arr, int l, int r) {
		int less = l - 1;
		int more = r;
		while (l < more) {
			if (arr[l] < arr[r]) {
				swap(arr, ++less, l++);
			} else if (arr[l] > arr[r]) {
				swap(arr, --more, l);
			} else {
				l++;
			}
		}
		swap(arr, more, r);
		return new int[] { less + 1, more };
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}
}

你可能感兴趣的:(LeetCode)