所有的排序算法总结

总结

在这里插入图片描述
这里是引用

  • n: 数据规模
  • k: “桶”的个数
  • In-place: 占用常数内存,不占用额外内存
  • Out-place: 占用额外内存

插入排序

  • 直接插入排序(Straight Insertion Sort)

思路:将一个记录插入到已经排好序的有序表中
动画演示:在这里插入图片描述
代码:
第一种方法:

void Straight_Insertion_Sort(int a[],int length){
	for (int i = 1;i < length;i++) 
	{
		if (a[i]<a[i-1]) {
			int temp = a[i];
			for (int j = i - 1;j >= 0;j--) {
				a[j + 1] = a[j];
				if (a[j] < temp) {
					a[j + 1] = temp;
					break;
				}
				if (j == 0 && a[j] > temp) {
					a[j] = temp;
				}
			}
		}
	}
}

第二种方法:

void Straight_Insertion_Sort(int a[],int length){
for (int i = 1;i < length;i++) {
		if (a[i] < a[i - 1]) {
			int j = i - 1;
			int temp = a[i];
			while (j>=0&&a[j]>temp) {
				a[j + 1] = a[j];
				j--;
			}
			a[j + 1] = temp;
		}
	}
}
  • 折半插入排序(Binary Insertion Sort)

思路: 插入排序主要是查找和插入两部分组成,其中查找元素的位置可以使用折半查找的办法
图片演示:
在这里插入图片描述

代码:

void Binary_Insert_Sort(int a[],int length) {
	int low, high, mid;
	int i, j,temp;
	for ( i = 1;i < length;i++) {
		low = 0;
		high = i - 1;
		temp = a[i];
		while (low<=high) {
			mid = (low + high) / 2;
			if (temp<a[mid]) {
				high = mid - 1;
			}
			else {
				low = mid + 1;
			}
		}//while
		for ( j = i - 1;j > high;j--) {
			a[j + 1] = a[j];
		}
		a[j + 1] = temp;
	}//for(i)
  • 2-路插入排序

思路: 在折半插入排序的基础上再改进,旨在减少关键字间的比较次数,而记录的移动次数不变

  • 希尔排序—缩小增量排序(Shell Sort)

思路: 通过增量的缩小使得待排序的记录从局部有序到全体有序。先将整个待排序记录分成若干个子序列分别进行直接插入排序,随着增量的缩减序列逐渐有序,当增量为1的时候对全体进行直接插入排序。增量的选择最好是531这样子,若是54321则会浪费很多时间。
动画演示:在这里插入图片描述

代码:

void Shell_Sort1(int a[], int length) {
	//首先定义一个初始增量,一般就是数组长度除以2或者3
	int gap = length / 2;
	while (gap >= 1) {
		for (int i = gap;i < length;i++) {
			int temp = a[i];
			int j = i;
			while (j >= gap&&temp<a[j - gap]) {
				a[j] = a[j - gap];
				j = j - gap;
			}//while
			a[j] = temp;
		}//for
		gap=gap/2;
	}//while
}

交换排序

  • 冒泡排序(Bubble Sort)

思路:两两比较元素,若顺序不同则交换,直到有序
演示:在这里插入图片描述

代码:

void Bubble_Sort(int a[],int length) {
	for (int i = 0;i < length - 1;i++) {
		for (int j = 0;j <length-i-1 ;j++) {
			if (a[j]>a[j+1]) {
				int temp = a[j];
				a[j] = a[j +1];
				a[j+1] = temp;
			}
		}
	}
}
  • 快速排序(Quick Sort)

思路: 找基准值,然后依次递归。一般就是小于基准值的放一边,大于基准值的放一边。然后每一边继续上述操作。主要是设两个指针,low和high,设置第一个或者最后一个为基准值(temp),比基准值大,high–,比基准值小,low++
演示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码:

//快速排序 需要两个函数配合
int Quick_Sort_GetKey(int a[],int low,int high) {
	int temp = a[low];
	while (low<high) {
		//首先比较队尾的元素和关键之temp,如果队尾大指针就往前移动
		while (low<high&&a[high]>=temp) {
			high--;
		}
		//当a[high]<temp的时候,跳出循环然后将值付给a[low],a[low]=temp
		a[low] = a[high];
		//赋值过一次之后就立刻从队首开始比较
		while (low<high&&a[low]<=temp) {
			low++;
		}
		a[high] = a[low];
	}//while (low<high)
	a[low] = temp;//或者a[high]=temp
	return low;
}
void Quick_Sort(int a[],int low,int high) {
	if (low<high) {
		int key = Quick_Sort_GetKey(a, low,high);
		Quick_Sort(a,low,key-1);
		Quick_Sort(a,key+1,high);
	}
}

选择排序

  • 简单选择排序(Select Sort)

思路: 在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数中再找最小(或者最大)的与第2个位置的数交换,以此类推,知道第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
图示:在这里插入图片描述

代码:

void Select_Sort(int a[],int length) {
	for (int i = 0;i < length - 1;i++) {
		int min_index = i;
		for (int j = i+1;j < length;j++) {
			if (a[min_index]>a[j]) {
				min_index = j;
			}
		}//for j
		if (i!=min_index) {
			int temp = a[i];
			a[i] = a[min_index];
			a[min_index] = temp;
		}
	}//for i
}
  • 堆排序(Heap Sort)

思路: 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
图示:
在这里插入图片描述
这篇文章说的很详细:链接
代码:

//index是第一个非叶子节点的下标(根节点)
//递归的方式构建
void Build_Heap(int a[],int length,int index){
	int left = 2 * index + 1;  //index的左子节点
	int right = 2 * index + 2;//index的右子节点
	int maxNode = index; //默认当前节点是最大值,当前节点index
	if (left<length&&a[left]>a[maxNode]) {
		maxNode = left;
	}
	if (right<length&&a[right]>a[maxNode]) {
		maxNode = right;
	}
	if (maxNode!=index) {
		int temp = a[maxNode];
		a[maxNode] = a[index];
		a[index] = temp;
		Build_Heap(a,length,maxNode);
	}

}
void Heap_Sort(int a[],int length) {
	for (int i = length / 2;i >= 0;i--) {
		Build_Heap(a, length, i);
	}
	for (int i = length - 1;i >= 1;i--) {
		//交换刚建好的大顶堆的堆顶和堆末尾节点的元素值,
		int temp = a[i];
		a[i] = a[0];
		a[0] = temp;
		//交换过得值不变,剩下的重新排序成大顶堆
		Build_Heap(a,i,0);
	} 
}

归并排序(Merging Sort)

  • 2-路归并排序

思路: 采用分治思想,将若干个已经排好序的子序合并成有序的序列。速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
图示:
在这里插入图片描述
代码:

//分治思想,先逐步分解成最小(递归)再合并
//归并
void Merge(int a[],int low,int mid,int high) {
	int i = low;
	int j = mid + 1;
	int k = 0;
	int *temp = new int[high - low + 1];
	while (i<=mid&&j<=high) {
		if (a[i]<=a[j]) {
			temp[k++] = a[i++];
		}
		else {
			temp[k++] = a[j++];
		}
	}//while (i<mid&&j<=high)
	while (i<=mid) {
		temp[k++] = a[i++];
	}
	while (j<=high) {
		temp[k++] = a[j++];
	}
	for (i = low, k = 0;i <= high;i++, k++) {
		a[i] = temp[k];
	}
	delete[] temp;
 }
//递归分开
void Merge_Sort(int a[], int low, int high) {
	if (low < high) {
		int mid = (low + high) / 2;
		Merge_Sort(a, low, mid);
		Merge_Sort(a, mid + 1, high);
		cout << "mid=" << mid <<" " <<a[mid]<< endl;
		cout << "low=" << low << " " << a[low] << endl;
		cout << "high=" << high << " " << a[high] << endl;
		cout << endl;
		//递归之后再合并
		Merge(a, low, mid, high);
	}
}
  • 多路归并排序

计数排序

思路: 空间换时间的思想,不是比较性质的,所以属于线性时间序列的算法,适用于适用于一定范围的整数排序。在取值范围不是很大的情况下,它的性能在某些情况甚至快过那些O(nlogn)的排序,例如快速排序、归并排序。其原理就是它不需要去跟其他元素比来比去,而是一开始就知道自己的位置,所以直接归位,在计数的该元素出现的词频数组里面,出现一次,就直接+1一次即可,如果没有出现改位置就是0,最后该位置的词频,就是代表其在原始数组里面出现的次数,由于词频数组的index是从0开始,所以最后直接遍历输出这个数组里面的每一个大于0的元素值即可。
图示: 在这里插入图片描述
代码:

void Count_Sort(int a[],int length) {
	//得到待排序的最大值
	int max = a[0];
	int i=0;
	while ( i<length-1) {
		max = (a[i] > a[i + 1]) ? a[i] : a[i + 1];
		i++;
	}
	int *countArray = new int[max + 1]{0};
	int *temp = new int[length];

	for (int i = 0;i < length;i++) {
		countArray[a[i]]++;
	}
	//!!!这一步的思想特别重要,在非比较排序中
	for (int i = 1;i < max+1;i++) {
		countArray[i] += countArray[i - 1];
	}
	//反向遍历
	for (int i = length - 1;i >= 0;i--) {
		temp[countArray[a[i]]-1] = a[i];
		countArray[a[i]]--;
	}
	for (int i = 0;i < length;i++) {
		a[i] = temp[i];
	}
	delete[] countArray;
	delete[] temp;
}

基数排序

思路: 按每一位的大小去排序,因为一位数的范围是0-9,就将每一位的数字提出来然后依次放入固定的十个桶子里,一次是个十百千位的顺序
图示:
在这里插入图片描述

代码:

int Get_Max_Digits(int a[],int length) {
	int max = a[0];
	int i = 0;
	while (i<length-1) {
		max = (a[i] > a[i + 1]) ? a[i] : a[i + 1];
		i++;
	}
	int b = 0;//最大值的位数
	while (max>0) {
		max = max / 10;
		b++;
	}
	return b;
}
//切记!桶子只能是十个,是定死的
void Radix_Sort(int b[],int length) {
	int d = Get_Max_Digits(b, length);//得到最大值的位数
	int * temp = new int[length];//开辟一个和原数组相同的临时数组
	//根据最大值的位数进行排序次数循环
	int radix = 1;
	for (int i = 0;i < d;i++) {
		//每次把数据装入桶子前先清空count
		int count [10] = { 0 }; //计数器 每次循环都清零
		for (int j = 0;j < length;j++) {
			//统计尾数为0-9的个数,一次是个十百千....位
			int tail_number = (b[j]/radix)%10;
			count[tail_number]++;//每个桶子里面的个数 
		}
		//桶中的每一个数的位置一次分配到temp数组中,先找到位置
		for (int j = 1;j < 10;j++) {
			count[j] += count[j - 1];
		}
		//分配到temp中排序后的位置
		for (int j = length - 1;j >= 0;j--) {
			int tail_number = (b[j] / radix) % 10;
			temp[count[tail_number] - 1] = b[j];
			count[tail_number]--;
		}
		//赋值
		for (int j = 0;j < length;j++) {
			b[j] = temp[j];
		}
		radix *= 10;
	}//for(int i)
	delete[] temp;
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值