【面试】排序算法小结

一、十大排序

排序算法

1、比较排序

1-1 初级排序( O ( n 2 ) O(n^2) O(n2)

1、冒泡: 嵌套循环,每次查看相邻元素,如果逆序,则交换。
冒泡排序

public void bubbleSort(int[] array) {
    
    
	int len = array.length;
	for (int i=len-1; i>=0; i--) {
    
    
		int flag = 0;
		for (int j=0; j<i; i++) {
    
    
			if (array[i]>array[j]) {
    
    
				int temp = array[i]; array[i] = array[j]; array[j] = temp;
				flag = 1;
			}
		}
		if (flag == 0) break;
	}
}

2、插入: 从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序

public insertSort(int[] arr) {
    
    
	int len = arr.length;
	for (int p=1; p<len; p++) {
    
    
		int temp = arr[p];
		for (int i=p; i>0 && A[i-1]>temp; i--) {
    
    
			arr[i] = arr[i-1];
		}
		a[i] = temp;
	}
}

3、希尔
希尔排序

public static int[] shellSort(int[] arr)
{
    
     	
	int len = arr.length;
	for (int gap=Math.floor(len/2); gap>0; gap = Math.floor(gap / 2)) {
    
      
	// 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
		for (int pos=gap; pos<len; pos++ ) {
    
     /* 插入排序*/
			int temp = arr[pos];
			for (int i=pos; i>=gap && arr[i-gap]>temp; i-=gap ) {
    
    
				arr[i] = arr[i-gap];
			}
			arr[i] = temp;
		}
	}
}

// 也可自定义增量序列解决,这里只列出一小部分增量
// int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
// for ( Si=0; Sedgewick[Si]>=N; Si++ );
// for ( D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] )

4、选择: 每次找最小值,然后放到待排序数组的起始位置。
选择排序

public static int[] selectionSort(int[] arr) {
    
    
    int len = arr.length;
    for(int p = 0; p < len - 1; p++) {
    
    
        int minIndex = p;
        for(int i = p+1; i < len; i++) {
    
    
            if(arr[i] < arr[minIndex]) {
    
         // 寻找最小的数
                minIndex = i;                // 将最小数的索引保存
            }
        }
        int temp = arr[p]; arr[p] = arr[minIndex]; arr[minIndex] = temp;
    }
    return arr;
} 
1-2 高级排序( O ( n l o g n ) O(nlogn) O(nlogn)

5、快排
快排

public static void quickSort(int[] array, int begin, int end) {
    
    
    if (end <= begin) return;
    int pivot = partition(array, begin, end);
    quickSort(array, begin, pivot - 1);
    quickSort(array, pivot + 1, end);
}

static int partition(int[] a, int begin, int end) {
    
    
    // pivot: 标杆位置,counter: 小于pivot的元素的个数
    int pivot = end, counter = begin;  
    for (int i = begin; i < end; i++) {
    
    
        if (a[i] < a[pivot]) {
    
    
            int temp = a[counter]; a[counter] = a[i]; a[i] = temp;
            counter++;
        }
    }
    int temp = a[pivot]; a[pivot] = a[counter]; a[counter] = temp;
    return counter;
}

6、归并
归并

public static void mergeSort(int[] array, int left, int right) {
    
    

	if (right <= left) return;
	int mid = (left + right) >> 1;  // (left+right)/2
	
	mergeSort(array, left, mid);
	mergeSort(array, mid+1, right);
	merge(array, left, mid, right);
}

public static void merge(int[] arr, int left, int mid, int right) {
    
    
	
	int[] temp = new int[right-left+1];  // 中间数组
	int i = left, j = mid+1, k = 0;
	
	while (i<=mid && j<=right) {
    
    
		temp[k++] = arr[i]<=arr[j] ? arr[i++] : arr[j++];
	}
	while (i<=mid)   temp[k++] = arr[i++];
	while (j<=right) temp[k++] = arr[j++];
	
	for (int p=0; p<temp.length; p++) {
    
    
		arr[left+p] = temp[p];
	}
	// 也可以用 System.arraycopy(a, start1, b, start2, length)
}

归并 VS 快排: 具有相似性,但步骤顺序相反。

归并:先排序左右子数组,然后合并两个有序子数组。
快排:先调配出左右子数组,然后对于左右子数组进行排序。

7、堆排序:插入 O ( l o g n ) O(logn) O(logn),取最大/小值 O ( 1 ) O(1) O(1)

S1:数组元素依次建立小顶堆;
S2:依次取堆顶元素,并删除。
堆排序

版本1–PriorityQueue():

void heapSort(int[] arr) {
    
    
	
	int len = arr.length;
	PriorityQueue<Integer> q = new PriorityQueue<>();

	for (int i=0; i<len; i++) {
    
    
		q.add(a[i]);
	}
	
	for (int i=0; i<len; i++) {
    
    
		a[i] = q.pop();
	}
}

版本2–手动实现:

static void heapify(int[] array, int length, int i) {
    
    
	int left = 2*i+1, right=2*i+2;
	int largest = i;
	
	if (left<length && array[left]>array[largest]) {
    
    
		largest = leftChild;
	}
	if (right<length && array[right]>array[largest]) {
    
    
		largest = right;
	}
	
	if (largest != i) {
    
    
		int temp = array; array[i] = array[largest]; array[largest] = temp;
		heapify[array, length, largest);
	}
}

public static void heapSort(int[] array) {
    
    
	if (array.length == 0) return;
	int length = array.length;
	for (int i = length/2-1; i>=0; i--) {
    
    
		heapify(array, length, i);
	}
	
	for (int i=length-1; i>=0; i--) {
    
    
		int temp = array[0]; array[0] = array[i]; array = temp;
		heapify(array, i, 0);
	}
}

2、非比较排序–特殊排序

8、计数排序
计数排序

public static int[] countSort(int[] arr, int maxValue) {
    
    
	int sortedIndex = 0;
	int[] bucket = new int[maxValue+1],
    for(int i = 0; i < arr.length; i++) {
    
    
        bucket[arr[i]]++;
    }
    for(int j = 0; j < maxValue+1; j++) {
    
    
        while(bucket[j] > 0) {
    
    
            arr[sortedIndex++] = j;
            bucket[j]--;
        }
    }
    return arr;
}

9、桶排序
桶排序

function bucketSort(arr, bucketSize) {
    
    
    if (arr.length === 0) {
    
    
      return arr;
    }
 
    var i;
    var minValue = arr[0];
    var maxValue = arr[0];
    for (i = 1; i < arr.length; i++) {
    
    
      if (arr[i] < minValue) {
    
    
          minValue = arr[i];                // 输入数据的最小值
      } else if (arr[i] > maxValue) {
    
    
          maxValue = arr[i];                // 输入数据的最大值
      }
    }
 
    // 桶的初始化
    var DEFAULT_BUCKET_SIZE = 5;            // 设置桶的默认数量为5
    bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
    var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;  
    var buckets = new Array(bucketCount);
    for (i = 0; i < buckets.length; i++) {
    
    
        buckets[i] = [];
    }
 
    // 利用映射函数将数据分配到各个桶中
    for (i = 0; i < arr.length; i++) {
    
    
        buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
    }
 
    arr.length = 0;
    for (i = 0; i < buckets.length; i++) {
    
    
        insertionSort(buckets[i]);                      // 对每个桶进行排序,这里使用了插入排序
        for (var j = 0; j < buckets[i].length; j++) {
    
    
            arr.push(buckets[i][j]);                     
        }
    }
 
    return arr;
}

10、基数排序
基数排序

var counter = [];
function radixSort(arr, maxDigit) {
    
    
    var mod = 10;
    var dev = 1;
    for(var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
    
    
        for(var j = 0; j < arr.length; j++) {
    
    
            var bucket = parseInt((arr[j] % mod) / dev);
            if(counter[bucket]==null) {
    
    
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);
        }
        var pos = 0;
        for(var j = 0; j < counter.length; j++) {
    
    
            var value = null;
            if(counter[j]!=null) {
    
    
                while((value = counter[j].shift()) != null) {
    
    
                      arr[pos++] = value;
                }
          }
        }
    }
    return arr;
}

二、参考

1、快速排序代码示例
2、十大经典排序算法(动图演示)
3、八个排序的原理、Java 实现以及算法分析
4、Java学习笔记–PriorityQueue(优先队列)(堆)

猜你喜欢

转载自blog.csdn.net/HeavenDan/article/details/109165069