八大排序算法
1、冒泡排序
思想:
(1)相邻两个元素依次比较,保证右边元素大于左边(小于则交换位置),一轮结束后保证最后一个元素一定是最大的元素
(2)对剩下n-1个元素再次执行(1)
(3)第n-1轮执行后序列排序完成
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 冒泡 | O(n) | O(n^2) | O(n^2) | O(1) | 数据量小,有序 | 稳定 |
实现代码:
public static void bubbleSort(int data[]) {
boolean didSwap;
for (int i = 0; i < data.length - 1; i++) {
didSwap = false;
for (int j = 0; j < data.length - i - 1; j++) {
if (data[j + 1] < data[j] ) {//加等于则不稳定
int temp = data[j + 1];
data[j + 1] = data[j];
data[j] = temp;
didSwap = true;
}
}
if (!didSwap) {
return;
}
}
}
2、 选择排序
思想:
(1)从序列中选出最大元素
(2)如果最大元素不是在最后一位,将其互换位置
(3)对剩下的n -1 个元素执行(1)(2)
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 直接选择 | O(n^2) | O(n^2) | O(n^2) | O(1) | 数据量小 | 稳定 |
注:选择排序稳定性跟代码实现方式有关,这种写法为稳定
代码:
public static int[] selectionSort(int data[]){
for (int i = 0; i < data.length -1; i++) {
int maxIndex = 0;
for (int j = 0; j < data.length - i; j++) {
if (data[j] >= data [maxIndex]) {//加等于稳定
maxIndex = j;
}
}
if (maxIndex != data.length - i -1) {
int temp = data[data.length - i -1];
data[data.length - i -1] = data[maxIndex];
data[maxIndex] = temp;
}
}
return data;
}
3、直接插入排序
思想:
(1)将第i元素与排好序的n个数的序列做比较(默认第一个元素为有序),如果有序序列中有元素比第i个位置的元素大,互换位置,直至排好序的所有元素与第i个位置的元素比较过则前n+1个元素有序
(2)重复(1), 直至整个序列有序
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 直接插入 | O(n) | O(n^2) | O(n^2) | O(1) | 数据量小,有序 | 稳定 |
代码:
public static int[] straightInsertionSort(int data[]) {
for (int i = 1; i < data.length ; i++) {
for (int j = 0; j < i; j++) {
if (data[j] > data [i]) {
int temp = data[j];
data[j] = data[i];
data[i]= temp;
}
}
}
return data;
}
4、希尔排序
思想:
(1)将元素通过步长分组,组内用直接插入排序使其有序
(2)随着步长逐渐减小,每个分组的记录数越来越多,当步长减为1时,所有记录合成一组,所有记录有序
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 希尔排序 | O(n^1.3) | O(n^2) | O(n^2) | O(1) | 数据量大 | 不稳定 |
代码:
public static int[] shellSort(int data[]) {
for (int gap = data.length/2; gap > 0; gap /=2) {
//保证初始前面只有一个元素使其有序 然后每次插入和之前有序序列比较
for (int i = gap; i < data.length; i++) {
straightInsertionSort(data,i,gap);
}
}
return data;
}
private static void straightInsertionSort(int[] data, int index, int gap) {
for (int j = index%gap; j <= index - gap; j += gap) {//同一组的和之前有序的元素比较交换
if (data[index] < data [j]) {
int temp = data[index];
data[index] = data[j];
data[j] = temp;
}
}
}
5、快速排序
思想:
(1)单次排序时,选择第一个元素为基准数,i,j分别指向第一个元素和最后一个元素,j先向前扫描,若data[j] 大于等于基准数,则继续往前扫描,当data[j]小于基准数时,基准数和data[j] 互换位置,i向后扫描,若data[i] 小于等于基准数,则继续往前扫描,当data[i]大于基准数时,基准数和data[i]] 互换位置,然后j继续向前扫描,i,j交替扫描,直至i == j,则一次排序完成
(2)一次排序使基准数左边小于基准数,右边大于基准数
(3)对于基准数左边和右边元素重复(1),(2)
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 快速排序 | O(nlog2n) | O(n^2) | O(nlog2n) | O(nlog2n) | 数据量大 | 不稳定 |
public static void quickSort(int data[],int low,int high) {
if (low < high) {
int middleIndex = getMiddleIndex(data,low,high);
quickSort(data,low,middleIndex - 1);
quickSort(data,middleIndex + 1,high);
}
}
private static int getMiddleIndex(int[] data, int low, int high) {
int key = data[low];
while (low < high) {
while (data[high] > key && low < high){
high --;
}
data[low] = data[high];
while (data[low] <= key && low < high) {
low ++;
}
data[high] = data[low];
}
data[low] = key;
return low;
}
6、堆排序
思想:
(1)将无序序列构造为大顶或者小顶堆,每次取出堆顶元素,将堆尾元素放在堆顶,再次调整为大顶堆或者小顶堆,直至堆只剩最后一个元素
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 数据量大 | 不稳定 |
代码:
public static void heapSort(int data[]) {
//建堆
//i 指向最后一个非叶子节点
for (int i = data.length/2 - 1; i >= 0; i --) {
adjustHeap(data,i,data.length);
}
for (int k = data.length -1; k > 0; k--) {
//把最大元素放到堆尾,此时只需调整根节点
swap(data,0,k);
adjustHeap(data,0,k);
}
}
//每个非叶子节点都要调整堆使之成为大顶堆,并循环调整所有子树
private static void adjustHeap(int[] data, int i, int length) {
for (int j = 2 * i + 1; j < length; j = 2 * j + 1) {
//判断右子节点是否存在,j 指向子节点中较大的
if (j + 1 < length && data[j] < data[j + 1]) {
j++;
}
if (data[j] > data[i]) {
swap(data,i,j);
//循环检查子树 只调整结构改变的
i = j;
} else {
break;
}
}
}
private static void swap (int data[],int i,int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
7、归并排序
思想:
利用分治思想递归求解,先分解成有序序列(每组只剩一个元素),然后每个有序序列合并,直至整个序列有序
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 数据量大 | 稳定 |
代码:
public static void mergeSort (int data[],int left,int right,int temp[]) {
if (left < right) {
int mid = (left + right)/2;
mergeSort(data,left,mid ,temp);
mergeSort(data,mid+1,right,temp);
merge(data,left,right,mid,temp);
}
}
private static void merge(int[] data, int left, int right, int mid, int[] temp) {
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
temp[k++] = data[i] <= data[j] ? data[i++]:data[j++];
}
if (i > mid){
while (k <= right) {
temp[k++] = data[j++];
}
}
if (j > right){
while (k <= right) {
temp[k++] = data[i++];
}
}
for (int m = left; m <= right; m++) {
data[m] = temp[m];
}
}
8、基数排序
思想:
从个位开始将排序的元素按个位的值放入0~9编号的桶中,再将得到的子序列按十位的值放入桶中,一直到最高位为止
| 算法 | 最好复杂度 | 最差复杂度 | 平均复杂度 | 空间复杂度 | 适用场景 | 稳定性 |
|---|---|---|---|---|---|---|
| 基数排序 | O(d*(n+r)) | O(d*(n+r)) | O(d*(n+r)) | O(n+r) | 数据量大 | 稳定 |
其中,d 为位数(代码中为count),r 为基数(10),n 为原数组个数(data.length)。
代码:
public static void radixSort(int data[]){
int places = getMaxPlaces(data);//最大数的位数
int bucket[][] = new int [10][data.length]; //十个桶
int bucketCount[] = new int[10];//每个桶数据量
for (int i = 0; i < places; i++) {
putBucket(data,i,bucketCount,bucket);
getBucket(data,bucketCount,bucket);
}
}
private static void getBucket(int[] data, int[] bucketCount, int[][] bucket) {
int k = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < bucketCount[i]; j++) {
data[k++] = bucket[i][j];
}
bucketCount[i] = 0;
}
}
//按第i位入桶
private static void putBucket(int[] data,int i,int bucketCount[],int bucket[][]) {
int index = 0;
for (int num : data) {
index = (int)(num/Math.pow(10,i))%10;
bucket[index][bucketCount[index]] = num;
bucketCount[index]++;
}
}
private static int getMaxPlaces(int[] data) {
int max = data[0];
for (int i = 1; i < data.length; i++) {
if (data[i] > max){
max = data[i];
}
}
int count = 0;
//取最大值的位数
while (max > 0) {
max = max/10;
count ++;
}
return count;
}
368

被折叠的 条评论
为什么被折叠?



