八大排序算法-C++实现

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

/*
	稳定:如果原本序列中a在b前面且a=b,排序后a仍在b前面,顺序不变;
	不稳定:如果原本序列中a在b前面且a=b,排序后a可能在b后面,顺序可能发生改变;
	内排序:所有排序操作均在内存中完成;
	外排序:由于数据量太大,将其放入磁盘中,排序过程中需要磁盘与内存之间的数据传输;
	时间复杂度:一个排序算法在执行过程中所耗费的时间量级的度量;
	空间复杂度:一个排序算法在运行过程中临时占用存储空间大小的度量
*/

//------------------------------------------------------分割线----------------------------------------------------//

//1、冒泡排序
void BubbleSort(int data[], int n) {
	int flag = 0;
	for (int i = 0; i < n; i++) {
		flag = 0;
		for (int j = 1; j < n; j++) {
			if (data[j] < data[j - 1]) {
				flag = 1;
				int t = data[j];
				data[j] = data[j - 1];
				data[j - 1] = t;
			}
		}
		if (flag == 0)return;
	}
}

//------------------------------------------------------分割线----------------------------------------------------//

//2、选择排序
//选择最大值的下标,然后交换
int findMax(int data[], int n) {
	int max = data[0];
	int pos = 0;
	for (int i = 1; i < n; i++) {
		if (data[i] > max) {
			max = data[i];
			pos = i;
		}
	}
	return pos;
}

void SelectSort(int data[], int n) {
	while (n > 1) {
		int pos = findMax(data, n);
		int tmp = data[n - 1];
		data[n - 1] = data[pos];
		data[pos] = tmp;
		n--;
	}
	return;
}

//------------------------------------------------------分割线----------------------------------------------------//

//3、插入排序
//对前2个,前3个,前n个以此插入排序
void InsertSort(int data[], int n) {
	int j;
	for (int i = 1; i < n; i++) {
		int key = data[i];
		for ( j= i; j > 0; j--) {
			if (j-1>=0 && data[j-1] > key) {
				data[j] = data[j - 1];
			}
			else break;
		}
		data[j] = key;
	}
}

void InsertSort2(int data[], int n) {
	int j;
	for (int i = 1; i < n; i++) {
		j = i;
		int tmp = data[i];
		while (j > 0) {
			if (tmp < data[j - 1]) {
				swap(data[j], data[j - 1]);
				//data[j] = data[j-1];
				j--;
			}
			else break;
		}
		//data[j] = tmp;
	}
}

//------------------------------------------------------分割线----------------------------------------------------//

//4、希尔排序
//确定一个步长,将数组变成部分有序,每一趟都采用插入排序
void ShellSort(int arr[], int n)
{
	int i, j, inc, key;
	//初始增量:n/2,每一趟之后除以2
	for (inc = n / 2; inc > 0; inc /= 2) {
		//每一趟采用插入排序
		for (int i = inc; i < n; i++) {
			key = arr[i];
			//每一组采用插入排序
			for (j = i; j >= inc && key < arr[j - inc]; j -= inc) {
				arr[j] = arr[j - inc];
			}
			arr[j] = key;
		}
	}

}

//------------------------------------------------------分割线----------------------------------------------------//

//5、堆排序
/*
	维护堆的性质:堆为完全二叉树,大顶堆指父节点的值大于子节点,小顶堆反之
	n : 数组长度
	i : 待维护节点的下标

	下标为i的节点的父节点下标: (i-1)/2
	下标为i的节点的左孩子下标:  i*2+1
	下标为i的节点的右孩子下标:  i*2+2
*/

//维护大顶堆
void headify(int arr[], int n, int i) {
	int largest = i;
	int lson = i * 2 + 1;
	int rson = i * 2 + 2;
	if (lson < n && arr[largest] < arr[lson]) {
		largest = lson;
	}
	if (rson < n&&arr[largest] < arr[rson]) {
		largest = rson;
	}
	if (largest != i) {
		swap(arr[largest], arr[i]);
		headify(arr, n, largest);
	}
}

//堆排序入口
void headSort(int arr[], int n) {
	//建堆
	for (int i = n / 2 - 1; i >= 0; i--) {
		headify(arr, n, i);
	}

	//排序
	for (int i = n - 1; i > 0; i--) {
		swap(arr[i], arr[0]);
		headify(arr, i, 0);
	}
}


//------------------------------------------------------分割线----------------------------------------------------//

//6、快速排序
//分治、双指针思想
//划分:选取最右边的值为基准

int partition(int arr[], int low, int high) {
	int pivot = arr[high];
	int i = low;
	for (int j = low; j < high; j++) {
		//比pibot小的,全部换到前面去
		if (arr[j] < pivot) {
			swap(arr[j], arr[i++]);
		}
	}
	//此时,i指向的元素一定大于等于pivot
	swap(arr[high], arr[i]);
	return i;
}

void qsort(int arr[], int low, int high) {
	if (low < high) {
		int mid = partition(arr, low, high);
		qsort(arr, low, mid - 1);
		qsort(arr, mid + 1, high);
	}
}

void quickSort(int arr[], int n) {
	qsort(arr, 0, n - 1);
}

//------------------------------------------------------分割线----------------------------------------------------//

//7、计数排序
void countSort(int arr[], int n) {
	if (n < 1)return;

	//寻找最大的元素
	int max = arr[0];
	for (int i = 0; i < n; i++) {
		if (arr[i] > max)max = arr[i];
	}

	//分配一个长度为max+1的数组存储计数,并初始化为0
	vector<int>count(max + 1, 0);

	//计数
	for (int i = 0; i < n; i++) {
		count[arr[i]]++;
	}

	//统计计数的累加值
	for (int i = 1; i < max + 1; i++) {
		count[i] += count[i - 1];
	}

	//创建一个临时数组保存结果
	int* tmp = (int*)malloc(n * sizeof(int));
	for (int i = 0; i < n; i++) {
		tmp[count[arr[i]]-1] = arr[i];
		count[arr[i]]--;
	}

	for (int i = 0; i < n; i++) {
		arr[i] = tmp[i];
	}

}

//------------------------------------------------------分割线----------------------------------------------------//
//8、归并排序

void merge(int arr[], int tmpArr[], int left, int mid ,int right){
	//标记左半区第一个未排序的元素
	int l_pos = left;
	//标记右半区第一个未排序的元素
	int r_pos = mid + 1;
	//临时数组元素的下标
	int pos = left;

	//合并
	while (l_pos <= mid && r_pos <= right) {
		if (arr[l_pos] < arr[r_pos]) {
			tmpArr[pos++] = arr[l_pos++];
		}
		else tmpArr[pos++] = arr[r_pos++];
	}

	//合并左半区剩余的元素
	while (l_pos <= mid) {
		tmpArr[pos++] = arr[l_pos++];
	}

	//合并右半区剩余的元素
	while (r_pos <= right) {
		tmpArr[pos++] = arr[r_pos++];
	}

	while (left <= right) {
		arr[left] = tmpArr[left];
		left++;
	}

}

//递归切分
void msort(int arr[], int tmpArr[], int left, int right) {
	//如果只有一个元素,那么就不需要划分
	if (left == right)return;

	if (left < right) {
		//找中间点
		int mid = left+(right-left)/2;
		msort(arr, tmpArr, left, mid);
		msort(arr, tmpArr, mid + 1, right);
		//合并已经排序的部分
		merge(arr, tmpArr, left, mid, right);

	}
}

//归并排序入口
void mergeSort(int arr[], int n) {
	
	//分配一个辅助数组
	//C风格:
	int* tmpArr = (int*)malloc(n * sizeof(int));
	if (tmpArr) {
		msort(arr, tmpArr, 0, n - 1);
		free(tmpArr);
	}
	else {
		printf("error: failed to allocate memory");
	}
}





int main() {
	
	int a[10] = { 3,2,4,1,5 ,10,8,6,7,9};
	//1、冒泡排序,时间复杂度最小O(n),最大为O(n^2),空间复杂度O(1)
	//BubbleSort(a, 5);

	//2、选择排序,平均时间复杂度为O(n^2),空间复杂度O(1),不稳定
	//SelectSort(a, 5);

	//3、插入排序,时间复杂度最小O(n),最大为O(n^2),空间复杂度O(1),稳定
	//InsertSort2(a, 10);

	//4、希尔排序,时间复杂度与选取的分组长度序列有很大关系,最好为O(n*log^2(n)),最小为O(n^2)
	//平均复杂度为O(n^3/2),空间复杂度为O(1),不稳定
	//ShellSort(a, 5);

	//5、堆排序,时间复杂度为O(n*logn),建堆复杂度为O(n),heapify复杂度为O(logn),空间复杂度为
	//O(1),不稳定
	headSort(a, 10);

	//6、快速排序,时间复杂度最小为O(n*logn),最大为O(n^2),平均为O(n*logn),空间复杂度为
	//O(logn),不稳定
	//quickSort(a, 5);

	//7、计数排序,时间复杂度为O(n+k) ,即n个0~k之间的数,空间复杂度为O(k),稳定
	//适用于对最大值不是很大的整型元素序列进行排序的情况
	//countSort(a, 5);

	//8、归并排序,时间复杂度为O(n*logn),每一层归并的时间复杂度为O(n),归并层数最大为O(logn + 1)
	//空间复杂度为O(n),稳定
	//mergeSort(a, 5);



	for (int i = 0; i < 10; i++) {
		cout << a[i] << " ";
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值