【面试】排序算法小结

一、十大排序

1、分类
排序算法

2、复杂度与稳定性比较
比较

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、快排

版本1:双向扫描
具体动画可以看陈越老师老师课程之子集划分
1

public void quickSort( int[] array, int left, int right ) {
     int low = left, high = right-1, pivot = array[right-1]; /* pivot: 选基准 */ 
     while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/
          while (array[++low] < pivot) ;
          while (array[--high] > pivot) ;
          if (low < high) swap(array, low, high);
          else break;
     }
     swap(array, low, right-1);   /* 将基准换到正确的位置 */ 
     quickSort(array, left, low-1 );    /* 递归解决左边 */ 
     quickSort(array, low+1, right );   /* 递归解决右边 */  
}
private void swap(int[] array, int i, int j) {
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}

版本2:单向扫描(对单向链表快速排序同样适用)

算法细节理解可参考视频【嘉伦讲算法】快速排序|单向链表|可能是最简洁的代码实现思路 | 给链表排序 | 快排
快排

private int[] quickSort(int[] arr, int left, int right) {
    if (left < right) {
        int partitionIndex = partition(arr, left, right);
        quickSort(arr, left, partitionIndex - 1);  /* partitionIndex=less-1==pivot, less-2/less-1均可。 */
        quickSort(arr, partitionIndex + 1, right);
    }
    return arr;
}

private int partition(int[] arr, int left, int right) {
    // 选第一个元素作为基准值(pivot)
    // 指针初始值 less=pivot+1, more=pivot+1,more跑得快
    // 1)arr[more] > arr[pivot], more++
    // 2)arr[more] < arr[pivot], swap(num, less, more),less++,more++
    int pivot = left;
    int less = pivot + 1;
    for (int more = pivot + 1; more <= right; more++) {
        if (arr[more] < arr[pivot]) {
            swap(arr, more, less);
            less++;
        }
    }
    swap(arr, pivot, less - 1);  /* 处理完结果:left~less-2, pivot=less-1, less~more=right */
    return less - 1;
}

private void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

拓展:单向链表快速排序

public ListNode sortList(ListNode head) {
    quickSort(head, null);
    return head;
}

public void quickSort(ListNode head, ListNode tail) {
    if (head == null || head.next == null || head == tail) return;
    ListNode pivot = head, lessPre = head, less = head.next, more = head.next;
    for ( ; more != tail; more = more.next) {
        if (more.val < pivot.val) {
            swap(more, less);
            lessPre = less;
            less = less.next;
        } 
    }
    swap(pivot, lessPre);
    quickSort(head, lessPre);
    quickSort(less, more);
}

public void swap(ListNode i, ListNode j) {
    int tmp = i.val;
    i.val = j.val;
    j.val = tmp;
}

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(优先队列)(堆)
5、快速排序 – 自实现
7、1.6 快速排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值