算法总结(一)——排序算法总结

目录

一、排序定义

1.输入:n个数,a1,a2,……,an

2.输出:n个数,a1',a2',……,an',使得a1'≤a2'≤……≤an'。

二、排序分类

1.in-place sort(不占用额外内存或占用常数内存):插入排序、选择排序、冒泡排序、堆排序、快速排序;

   out-place sort:归并排序、计数排序、基数排序、桶排序。

2.稳定排序:插入排序、冒泡排序、归并排序、基数排序、计数排序、桶排序;

   不稳定排序:选择排序、快速排序、堆排序。

   稳定性:如果ai=aj,排序前ai在aj之前,排序后ai还在aj之前。

3.比较排序:冒泡排序、选择排序、插入排序、归并排序、堆排序、快速排序;

   非比较排序:计数排序、基数排序、桶排序。

三、常见排序算法性能

排序方法平均情况最好情况最坏情况辅助空间稳定性
冒泡排序O(n^2)O(n)O(n^2)O(1)稳定
简单选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
直接插入排序O(n^2)O(n)O(n^2)O(1)稳定
希尔排序O(nlogn)—O(n^2) O(n^2)O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
快速排序O(nlogn)O(nlogn)O(n^2)O(logn)—O(n)不稳定
      
      
      

四、冒泡排序

1.重复地走访过要排序的元素,依次比较相邻的两个元素,如果他们的顺序错误就把它们调换过来,知道没有元素在需要交换,排序完成。

2.图解

3.编程实现

//分类——内部比较排序
//数据结构——数组
//最差时间复杂度——O(n^2)
//最优时间复杂度——O(n)
//平均时间复杂度——O(n^2)
//辅助空间——O(1)
//稳定性——稳定

public class BubbleSort {
	
	public static void Swap(int[] a, int i, int j) {
		int temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}
	
	public static void bubbleSort(int[] a, int n) {
		for(int i = 0; i < n - 1; i++) {
			for(int j = 0; j < n - 1 - i; j++) {
				if(a[j] > a[j + 1]) {
					Swap(a, j, j + 1);
				}
			}
		}

	}

}

4.冒泡排序改进——鸡尾酒排序

(1)鸡尾酒排序,也叫定向冒泡排序,与传统的冒泡排序的区别在于从低到高比较然后从高到低比较。

(2)代码实现

public class CocktailSort {
	
	public static void cocktailSort(int[] a, int n) {
		int left = 0;
		int right = n - 1;
		while (left < right) {
			for(int i = left ; i < right; i++) {
				if(a[i] > a[i + 1]) {
					new Swap();
					Swap.swap(a, i, i + 1);
				}
			}
			right--;
			for(int i = right; i > left; i--) {
				if(a[i - 1] > a[i]) {
					new Swap();
					Swap.swap(a, i - 1, i);
				}
			}
			left++;
		}
	}

}

五、选择排序

1.初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列,然后再从剩余未排序序列中继续寻找最小(大)元素,以此类推。

2.图解

3.代码实现

//分类——内部比较排序
//数据结构——数组
//最差时间复杂度——O(n^2)
//最优时间复杂度——O(n^2)
//平均时间复杂度——O(n^2)
//辅助空间——O(1)
//稳定性——不稳定

public class SelectionSort {
	
	public static void selectionSort(int[] a, int n) {
		
		for(int i = 0; i < n - 1; i++) {
			int min = i;
			for(int j = i + 1; j < n; j++) {
				if(a[j] < a[min]) {
					min = j;
				}
			}
			if(min != i) {
				new Swap();
				Swap.swap(a, min, i);
			}
		}

	}

}

六、插入排序

1.将未排序数据,在已排序序列中从后向前扫描,找到相应位置插入。

2.代码实现:

//分类——内部比较排序
//数据结构——数组
//最差时间复杂度——降序序列O(n^2)
//最优时间复杂度——升序序列O(n)
//平均时间复杂度——O(n^2)
//辅助空间——O(1)
//稳定性——稳定

public class InsertSort {
	
	public static void insertSort(int[] a, int n) {
		for(int i = 1; i < n; i++) {
			int get = a[i];
			int j = i - 1;
			while (j >= 0 && a[j] >= get) {
				a[j + 1] = a[j];
				j--;
			}
			a[j + 1] = get;
		}
		new Display();
		Display.display(a, n);
	}

}

3.插入排序的改进——二分插入排序

(1)代码实现:

//最优时间复杂度——O(nlogn)

public class InsertSortDichotomy {
	
	public static void insertSortDichotomy(int[] a, int n) {
		for (int i = 1; i < n; i++) {
			int get = a[i];
			int left = 0;
			int right = i - 1;
			while (left <= right) {
				int mid = (left + right) / 2;
				if(a[mid] > get) {
					right = mid - 1;
				}
				else {
					left = mid + 1;
				}
			}
			for(int j = i - 1; j >= left; j--) {
				a[j + 1] = a[j];
			}
			a[left] = get;
		}
		new Display();
		Display.display(a, n);
	}

}

4.插入排序的更高效改进——希尔排序

1.希尔排序,也叫作递减增量排序。

2.图解:

3.代码实现:

//最差时间复杂度—根据步长不同而不同
//最优时间复杂度——O(n)
//平均时间复杂度——根据步长不同而不同
//稳定性——不稳定

public class ShellSort {
	
	public static void shellSort(int[] a, int n) {
		for(int gap = n / 2; gap > 0; gap /= 2) {
			for(int i = 0; i < gap; i ++) {
				for(int j = i + gap; j < n; j += gap) {
					if (a[j] < a[j - gap]) {
						int temp = a[j];
						int k = j - gap;
						while (k >= 0 && a[k] > temp) {
							a[k + gap] = a[k];
							k = k - gap;
						}
						a[k + gap] = temp;
					}
				}
			}
		}
		new Display();
		Display.display(a, n);
	}

}

七、堆排序

1.利用对这种数据结构所设计的一种选择排序算法,堆是一种近似完全二叉树的结构(通常堆是一维数组来实现的),并满足性质,以最大堆(也叫大根堆、大顶堆)为例,其父节点的值总是大于它的孩子节点。

2.步骤

(1)用输入的无序数组构造一个最大堆,作为初始的无序区;

(2)把最大值即堆顶元素和堆尾元素互换;

(3)把堆(无序区)的尺寸缩小1,并调用heapify从新的堆顶元素开始调整;

(4)重复步骤2,直到堆的尺寸为1。

3.代码实现

public class HeapSort {
	
	public static void heapify(int[] a, int i, int n) {
		int temp = a[i];
		for(int k = 2 * i + 1; k < n; k = 2 * k + 1) {
			if(k + 1 < n && a[k] < a[k + 1]) {
				k++;
			}
			if(a[k] > temp) {
				a[i] = a[k];
				i = k;
			}
		}
		a[i] = temp;
	}
	
	public static void heapSort(int[] a, int n) {
		for(int i = n / 2 - 1; i >= 0; i--) {
			heapify(a, i, n);
		}
		for(int j = n - 1; j > 0; j--) {
			new Swap();
			Swap.swap(a, 0, j);
			heapify(a, 0, j);
		}
	}

}

八、快速排序

1.快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序n个元素要O(nlogn)次比较。在最坏状况下则需要O(n^2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(nlogn)算法更快,因为它的内部循环可以在大部分的架构上很有效率地被实现出来。

2.快速排序使用分治策略(Divide and Conquer)来把一个序列分为两个子序列。步骤为:

(1).从序列中挑出一个元素,作为"基准"(pivot).

(2).把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。

(3).对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。

3.代码实现

public class QuickSort {
	
	public static void quickSort(int[] a, int low, int high) {
		if(low < high) {
			return;
		}
		int i = low;
		int j = high;
		int key = a[low];
		while (i < j) {
			while (a[j] < key && i < j) {
				j--;
			}
			while (a[i] > key && i < j) {
				i++;
			}
			if(i < j) {
				new Swap();
				Swap.swap(a, i, j);
			}
		}
		Swap.swap(a, low, i);
		quickSort(a, low, i - 1);
		quickSort(a, i + 1, high);
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值