七大排序算法

选择排序
根据自身的需求,选择的一种排序方法,如:从小到大排序,或从大到小排序

#include <iostream>


#define Type int

//位置交换函数
void swap(Type* ptr1, Type* ptr2) {
	Type tmp = *ptr1;
	*ptr1 = *ptr2;
	*ptr2 = tmp;
}

//实现排序(从后面开始大到小排序)
void selectSort(Type array[], int length) {
	for (int i = 0; i < length - 1; i++) {
		int max = 0;
		for (int k = 1; k < length - 1; k++) {//查找未排序的元素

			if (array[k] > array[max]) {//找到目前最小值

				max = k;//记录最大值
			}
		}

		//把最大的值一直往后放
		if (max != (length - i - 1)) {
			swap(&array[max], &array[length - i - 1]);
		}
	}
}

//从前面开始从小到大
void SelectSort(Type *arr, int len) {
	for (int i = 0; i < len - 1; i++) {
		int min = i;
		for (int k = i + 1; k < len; k++) {//查找未排序的元素

			if (arr[k] < arr[min]) {//找到最小值
				min = k;//记录最小值
			}
		}

		swap(&arr[min], &arr[i]);
	}
}

//测试代码
int main(void) {
	
	Type arr[] = { 5,3,9,15,20,90,34,61 };
	int len = sizeof(arr) / sizeof(arr[0]);

	printf("从小到大的顺序为:\n");
	selectSort(arr, len);
	for (int i = 0; i <len ; i++) {
		printf("%d%c", arr[i],',');
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述
冒泡排序
通过重复地遍历未排序的数列,一次比较两个元素,如果它们的顺 序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列 已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢得像泡泡一样“浮”到数 列的顶端,

#include <iostream>


#define Type char

//位置交换函数
void swap(Type* ptr1, Type* ptr2) {
	Type tmp = *ptr1;
	*ptr1 = *ptr2;
	*ptr2 = tmp;
}

void bubblingSort(Type* arr, int length) {

	for (int i = 0; i < length; i++) {

		bool out = true;//减少重复的排列次数条件

		for (int k = 0; k < length - 1 - i; k++) {

			if (arr[k] > arr[k + 1]) {
				swap(&arr[k], &arr[k + 1]);
				out = false;
			}
		}

		if (out == true) {
			break;
		}
	}
}

//测试代码
int main(void) {
	//字符是根据ASCLL码表的大小排序的
	Type arr[] = { 'a','A','R','Q','K','P','B','c' };
	int len = sizeof(arr) / sizeof(arr[0]);

	printf("从小到大的顺序为:\n");
	bubblingSort(arr, len);
	for (int i = 0; i <len ; i++) {
		printf("%c%c", arr[i],',');
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述
插入排序
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描, 找到相应位置并插入。插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1)的额外空间 的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供 插入空间。

#include <iostream>


#define Type int

void insertSort(Type* arr, int len) {
	int cur=0;
	int sur = 0;

	for (int i = 1; i < len; i++) {
		
		cur = i - 1;//空出来的第一个位置
		sur = arr[i];//保存第i个元素的临时变量

		//把后面的元素和前面的进行比较然后插入
		while (cur >= 0 && arr[cur] > sur) {//进行比较
			arr[cur + 1] = arr[cur];//进行排列
			cur--;
		}

		//当上面的条件不满足时,如:cur=-1时,那么第一个位置保存的就是最小或最大的元素了
		arr[cur + 1] = sur;
	}

}

//测试代码
int main(void) {
	//字符是根据ASCLL码表的大小排序的
	Type arr[] = { 'a','A','R','Q','K','P','B','c' };
	int len = sizeof(arr) / sizeof(arr[0]);

	printf("从小到大的顺序为:\n");
	insertSort(arr, len);
	for (int i = 0; i <len ; i++) {
		printf("%d%c", arr[i],',');
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述
希尔排序
希尔排序是希尔(Donald Shell)于 1959 年提出的一种排序算法。希尔排序也是一种插入排 序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。它与插入排序 的不同之处在于,它会优先比较距离较远的元素。 希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐 渐减少,每组包含的元素越来越多,当增量减至 1 时,所有元素被分成一组,实际上等同于执行一 次上面讲过的插入排序,算法便终止。
希尔排序的基本步骤:
选择增量 :gap=length/2,
缩小增量:gap = gap/2
增量序列:用序列表示增量选择,{n/2, (n/2)/2, …, 1} 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,
具体算法描述: 选择一个增量序列 ti,tj,…,tk,其中 ti>tj,tk=1;
按增量序列个数 k,对序列进行 k 趟排序;
每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进 行直接插入排序;
仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

#include <iostream>


#define Type int

void shellSort(Type* arr, int len) {
	int gap = len / 2;

	for (; gap > 0; gap /= 2) {//增量,依次按除以2的范围缩小

		for (int i = gap; i < len; i++) {
			int cur = arr[i];

			int k = 0;
			for (k = i - gap; k >= 0 && arr[k] > cur; k -= gap) {//进行条件比较
				arr[k + gap] = arr[k];//大的和小的位置调换
			}

			arr[k + gap] = cur;//排列
		}
	}
}

//测试代码
int main(void) {
	//字符是根据ASCLL码表的大小排序的
	Type arr[] = { 'a','A','R','Q','K','P','B','c',1,2 };
	int len = sizeof(arr) / sizeof(arr[0]);

	printf("从小到大的顺序为:\n");
	shellSort(arr, len);
	for (int i = 0; i <len ; i++) {
		printf("%d%c", arr[i],',');
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述
堆排序
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特 点快速定位指定索引的元素. (选择排序工作原理 - 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置, 然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待 排序的数据元素的个数为零)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

using namespace std;

#define DEFAULT_CAPCITY 64
typedef int DataType;
#define Less(a,b) (a<b)

//创建一个堆数组
typedef struct _Heap {
	DataType* arr;//存储堆元素的数组
	int size;//当前已存储的元素个数
	int capacity;//当前存储的容量
}Heap;

//初始化堆
bool initHeap(Heap& heap, DataType* orginal, int size);
//删除元素
bool popMax(Heap& heap, DataType&val);
//建立一个堆
static void buildHeap(Heap& heap);
//调整父节点的下一个位置元素
static void adjustDown(Heap& heap, int index);

bool initHeap(Heap& heap, DataType* orginal, int size) {
	/*int capacity = DEFAULT_CAPCITY > size ? DEFAULT_CAPCITY : size;

	heap.arr = new DataType[capacity];*/
	heap.arr = orginal;
	if (!heap.arr) {
		return false;
	}

	heap.capacity = size;
	heap.size = size;

	//如果存在原始数据则构建堆
	if (size > 0) {
		//方式1: 直接调整所有元素
		/*memcpy(heap.arr, orginal, size * sizeof(int));
		heap.size = size;*/
		//建堆
		buildHeap(heap);

		//方式2: 一次插入一个
		/*for (int i = 0; i < size; i++) {
			insert(heap, orginal[i]);
		}*/
	}
	return true;
}
bool popMax(Heap& heap, DataType&val){
	if (heap.size == NULL) {
		return false;
	}
	//获取堆中最大的元素,然后把堆中最后的一个元素放到最大元素的位置
	//再进行堆排列
	val=heap.arr[0];
	heap.arr[0] = heap.arr[--heap.size];
	adjustDown(heap, 0);

	return true;
}
//从最后一个父节点(size/2-1的位置)逐个往前调整所有父节点(直到根节点)
//确保每一个父节点都是一个最大堆,最后整体上形成一个最大堆
void buildHeap(Heap& heap) {
	for (int i = heap.size / 2 - 1; i >= 0; i--) {
		adjustDown(heap, i);
	}
}

//将当前的节点和子节点调整成最大堆
void adjustDown(Heap& heap, int index) {
	int cur = heap.arr[index];//当前待调整的节点
	int parent;
	int child;
	//判断是否存在大于当前节点子节点,如果不存在,则堆本身是平衡的,不需要调整;
	//如果存在,则将最大的子节点与之交换,交换后,如果这个子节点还有子节点
	//则要继续按照同样的步骤堆这个子节点进行调整
	for (parent = index; Less((parent * 2 + 1), heap.size); parent = child) {
		child = parent * 2 + 1;
		//取两个子节点中的最大的节点
		if ((Less((child + 1),heap.size) && Less(heap.arr[child], heap.arr[child + 1]))) {
			child++;
		}
		//判断最大的节点是否大于当前的父节点
		if (Less(heap.arr[child],cur)) {
			//不大于,则不需要整理,跳出循环
			break;
		}
		else {
			//大于当前的父节点,进行交换,然后从子节点位置继续下调整
			heap.arr[parent] = heap.arr[child];
			heap.arr[child] = cur;
		}
	}
}

//实现堆排序
void heapsort(Heap& heap) {
	if (heap.size < 1) {
		return;
	}
	while (heap.size > 0) {
		int tmp = heap.arr[0];
		heap.arr[0] = heap.arr[heap.size - 1];
		heap.arr[heap.size-1] = tmp;
		heap.size--;

		adjustDown(heap, 0);
	}
}

int main(void) {

	Heap hp;
	int origvals[] = { 2,3,6,9,11,80,45 };

	if (!initHeap(hp, origvals, sizeof(origvals) / sizeof(origvals[0]))) {
		fprintf_s(stderr, "初始化堆失败!\n");
		exit(-1);
	}
	for (int i = 0; i < hp.size; i++) {
		cout << i << "个元素:" << hp.arr[i] << endl;
	}
	heapsort(hp);

	for (int i = 0; i < sizeof(origvals)/sizeof(origvals[0]); i++) {
		cout <<"元素:" << origvals[i] << endl;
	}

	cout << "最大的3个元素:";
	for (int i = sizeof(origvals) / sizeof(origvals[0])-1; i > (sizeof(origvals) / sizeof(origvals[0]))-4; i--) {
		cout << origvals[i]<<",";
	}
	cout << endl;
	cout << "最小的3个元素:";
	for (int i = 0; i < 3; i++) {
		cout << origvals[i] << ",";
	}
	cout << endl;
	
	system("pause");
	return 0;
}

归并排序
当两个数组的元素需要合并在一块时,同时把两个数组的元素按需求排序的时候就可以使用归并排序

#include <iostream>


#define Type int

void mergeAdd(Type* arr, int left, int mid, int right, Type* tmp) {
	int i = left;//指向左边数组最小的元素位置
	int j = mid;//指向右边数组最小的元素位置
	int k = left;//临时数组的下标

	while (i < mid && j <= right) {//进行细分
		if (arr[i] < arr[j]) {//先比较细分出的大小存进数组
			tmp[k++] = arr[i++];
		}
		else {
			tmp[k++] = arr[j++];
		}
	}

	while (i < mid) {//排列左边部分的元素
		tmp[k++] = arr[i++];
	}

	while (j <= right) {//排列右边部分的元素
		tmp[k++] = arr[j++];
	}

	//把tmp中的内容拷贝到arr数组中,arr+1考虑到的是下面要进行递归分治排序的数组下标要明确
	memcpy(arr + left, tmp + left, sizeof(Type) * (right - left + 1));
}
//归并排序
void mergeSort(Type* arr, int left, int right, Type* tmp) {
	int mid = 0;

	if (left < right) {
		mid = left + (right - left) / 2;//获取中间位置
		mergeSort(arr, left, mid, tmp);//排序左边元素
		mergeSort(arr, mid+1,right, tmp);//排序右边元素
		mergeAdd(arr, left, mid + 1, right, tmp);//合并左右的结果
	}
}

//测试代码
int main(void) {

	Type arr[] = {1,2,6,3,9,11,16,12,8 };
	int len = sizeof(arr) / sizeof(arr[0]);
	Type* tmp = new Type[len];

	printf("从小到大的顺序为:\n");
	mergeSort(arr,0, len-1,tmp);
	for (int i = 0; i <len ; i++) {
		printf("%d%c", arr[i],',');
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述
快速排序

  1. 每次选取第一个数为基准数;
  2. 然后使用“乾坤挪移大法”将大于和小于基准的元素分别放置于基准数两边;
  3. 继续分别对基准数两侧未排序的数据使用分治法进行细分处理,直至整个序列有序。
    第一步:先选择第一个元素为基准数,以元素为基准将小于它的数排在它前面,大于等于它 的数排在其后,
    第二步:采用分治法分别对基数左边和右边的部分运用第一步中的方法进行递归操作,直到整个 数组变得有序,以左边的数组为例
#include <iostream>


#define Type int

//获取基数,实现左边比基数小,右边大于或等基数
int partition(Type* arr, int low, int high) {
	int i = low;
	int j = high;
	int base = arr[low];

	if (low < high) {
		while (i < j) {

			while (i < j && arr[j] >= base) {
				j--;
			}

			if (i < j) {//右边已经找到小于基数的元素
				arr[i++] = arr[j];
			}

			while (i < j && arr[i] < base) {
				i++;
			}

			if (i < j) {//左边已经找到大于基数的元素
				arr[j--] = arr[i];
			}
		}

		arr[i] = base;
	}

	return i;
}

//实现快速排序
void quickSort(Type* arr, int low, int higt) {
	if (low < higt) {
		int index = partition(arr, low, higt);

		//使用递归实现左右排序
		quickSort(arr, low, index - 1);
		quickSort(arr, index+1, higt);
	}
}

//测试代码
int main(void) {

	Type arr[] = {1,2,6,3,9,11,16,12,8 };
	int len = sizeof(arr) / sizeof(arr[0]);

	printf("从小到大的顺序为:\n");
	quickSort(arr, 0, len - 1);
	for (int i = 0; i <len ; i++) {
		printf("%d%c", arr[i],',');
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述

排序算法企业级应用
在这里插入图片描述
图中的n表示数组中的元素个数,O表示时间的使用,log n表示2的元素个数n的次方;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值