赞
踩
目录
排序 : 所谓排序就是使一串无序的数据进行排序后,变为递增或递减的数列.
稳定性 : 若有一组数据 : (为了看出效果,我加了一个标识符 a 与 b)编辑
我们可以看出第一幅图排序后 : 相同的两个数字5它们的前后顺序还是原来的顺序(a下标的5 还是在 b下标5的前面). 这是我们就认为它是一个稳定的排序
但是第二幅图排序后 : (b下标的5 在 a下标5的前面). 这是我们就认为它是不稳定的排序.
常见的排序有以下几种 : 直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序.
插入排序的基本思想 :
接下来我用画图来具体演示一下它是如何进行排序的 :
首先我们先定义两个下标 : i j
让 i 从1下标开始往后走. 把 i 下标的值给到 temp ; 让 j 每次都等于 i - 1,然后比较 j 下标的值 与 temp的值 ; 如果符合条件(具体情况看要排递减的还是要递增),那么就让 j 下标的值给到 j + 1下标,
然后让 j-- , 再重复比较 , 直到不符合条件,就退出比较,让i++进行下一轮比较.
这里我们排一个递增的数列(从小到大)
经过上面的分析 : 我们可以写出一下代码 :
- public void insertSort(int[] array) {
- for (int i = 1; i < array.length; i++) {
- int temp = array[i];
- for (int j = i - 1; j >= 0; j--) {
- if (array[j] > temp) {
- array[j + 1] = array[j];
- } else {
- array[j + 1] = temp;
- break;
- }
- }
- }
- }
但是结果确实不尽人意的,问题在这 :
综上 得出新的代码 :
- public void insertSort(int[] array) {
- for (int i = 1; i < array.length; i++) {
- int temp = array[i];
- int j = i - 1;
- for (; j >= 0; j--) {
- if (array[j] > temp) {
- array[j + 1] = array[j];
- } else {
- array[j + 1] = temp;
- break;
- }
- }
- array[j + 1] = temp;
- }
- }
插入排序的时间复杂度 : O(n^2)
空间复杂度 : O(1)
稳定性 : 稳定
插入排序的优点在于如果数据趋于有序的情况下,那么插入排序会更快.
这就是插入排序了!!!!!
希尔排序就是对直接插入排序的优化.
它的排序方法就是把一组数分为多个组.
例如 : 把它先分为5组 然后让他们每组进行插入排序,这样每组内的数就是有序了
然后再分为2组 然后让他们每组进行插入排序
最后整体看做是一组 然后进行插入排序
这样的话就会有个问题,分组我们怎么去分,最官方的解释 : 就是到目前为止还没有一个公式可以去计算分多少组最合适.因此我们分组的话,让gap的初始值等于数组的长度除以2,接下来每次组内比较完之后,再让 gap = gap / 2,直到 gap == 1 整体看做一组进行插入排序.
- /**
- * 希尔排序
- * 时间复杂度 : O(n^1.3)
- * 空间复杂度 : O(1)
- * @param array
- */
- public void shellSort(int[] array) {
- int gap = array.length / 2;
- while (gap > 0) {
- shell(array,gap);
- gap = gap / 2;
- }
- }
- public void shell(int[] array, int gap) {
- for (int i = gap; i < array.length; i++) {
- int temp = array[i];
- int j = i - gap;
- for (; j >= 0; j -= gap) {
- if(array[j] > temp) {
- array[j + gap] = array[j];
- } else {
- break;
- }
- }
- array[j + gap] = temp;
- }
- }
希尔排序的时间复杂度 : O(n ^ 1.3)
空间复杂度 : O(1)
稳定性 : 不稳定
这就是希尔排序了!!!!
基本思想 :
- /**
- * 选择排序
- * 时间复杂度 : O(n^2)
- * 空间复杂度 : O(1)
- * 稳定性 : 不稳定
- */
- public void selectSort(int[] array) {
- for (int i = 0; i < array.length; i++) {
- int minIndex = i;
- for (int j = i + 1; j < array.length; j++) {
- if (array[j] < array[minIndex]) {
- minIndex = j;
- }
- }
- swap(array,i,minIndex);
- }
- }
- //交换
- public void swap (int[] array, int x, int y) {
- int temp = array[x];
- array[x] = array[y];
- array[y] = temp;
- }
选择排序也可以进行优化 : 上面的每次遍历数组后只能得到一个最小值的下标, 我们可以 再加一个最大值的下标.这样每次内循环之后我们就可以确定两个下标的值.
- //选择排序的优化
- public void selectSort(int[] array) {
- for (int left = 0, right = array.length - 1; left < right; left++, right--) {
- int minIndex = left;
- int maxIndex = right;
- for (int j = left; j <= right; j++) {
- if (array[j] < array[minIndex]) {
- minIndex = j;
- }
- if (array[j] > array[maxIndex]) {
- maxIndex = j;
- }
- }
- swap(array,minIndex,left);
- if (maxIndex == left) {
- maxIndex = minIndex;
- }
- swap(array,maxIndex,right);
- }
-
- }
-
- //交换
- public void swap (int[] array, int x, int y) {
- int temp = array[x];
- array[x] = array[y];
- array[y] = temp;
- }
选择排序的时间复杂度 : O(n^2)
空间复杂度 : O(1)
稳定性 : 不稳定
以上就是选择排序!!!.
由上面的动图,每次遍历一次数组后就会确定一个最大或者最小的值.
- //冒泡排序
- public void bubbleSort(int[] array) {
- for (int i = 0; i < array.length - 1; i++) {
- boolean flag = true;
- for (int j = 0; j < array.length - 1 - i; j++) {
- if (array[j + 1] < array[j]) {
- swap(array,j+1,j);
- flag = false;
- }
- }
- if (flag) {
- break;
- }
- }
- }
- //交换
- public void swap (int[] array, int x, int y) {
- int temp = array[x];
- array[x] = array[y];
- array[y] = temp;
- }
冒泡排序的时间复杂度 : O(n^2)
空间复杂度 : O(1)
稳定性 : 稳定
以上就是冒泡排序了!!!
因为我们要排升序因此我们就先要把下面这个堆建成大根堆
通过向下调整 建大根堆:
- //建堆(使用向下调整建堆的时间复杂度为O(n))
- public void createHeap(int[] array) {
- for (int parent = (array.length - 1 -1) / 2; parent >= 0; parent--) {
- shiftDown(array,parent,array.length - 1);
- }
- }
- //向下调整 (时间复杂度 : O(logn))
- public void shiftDown(int[] array, int parent, int end) {
- int child = parent * 2 + 1;
- while (child <= end) {
- if ((child + 1 <= end) && (array[child + 1] > array[child])) {
- child++;
- }
- if (array[parent] < array[child]) {
- swap(array,parent,child);
- parent = child;
- child = parent * 2 + 1;
- } else {
- break;
- }
- }
- }
- //交换
- public void swap (int[] array, int x, int y) {
- int temp = array[x];
- array[x] = array[y];
- array[y] = temp;
- }
每次让0下标跟最后一个下标交换,交换完之后最后一个下标就不再参与调整.然后再把0下标向下调整确保它是一个大根堆.
- /**
- * 堆排序
- * 时间复杂度 : O(nlogn)
- * 空间复杂度 : O(1)
- * 稳定性 : 不稳定
- * @param array
- */
- public void heapSort(int[] array) {
- for (int i = array.length - 1; i > 0; i--) {
- swap(array,0,i);
- shiftDown(array,0,i - 1);
- }
- }
- //向下调整 (时间复杂度 : O(logn))
- public void shiftDown(int[] array, int parent, int end) {
- int child = parent * 2 + 1;
- while (child <= end) {
- if ((child + 1 <= end) && (array[child + 1] > array[child])) {
- child++;
- }
- if (array[parent] < array[child]) {
- swap(array,parent,child);
- parent = child;
- child = parent * 2 + 1;
- } else {
- break;
- }
- }
- }
- //交换
- public void swap (int[] array, int x, int y) {
- int temp = array[x];
- array[x] = array[y];
- array[y] = temp;
- }
堆排序的时间复杂度 : O(nlogn)
空间复杂度 :O(1)
稳定性 : 不稳定
以上就是堆排序!!!
快速排序就是去重复这个步骤.递归左边和右边
- /**
- * 快速排序
- * 时间复杂度 : O(nlogn)
- * 空间复杂度 : O(logn)
- * 稳定性 : 不稳定
- * @param array
- */
- public void quickSort(int[] array) {
- quick(array,0,array.length - 1);
- }
- public void quick(int[] array, int s, int e) {
- if (s >= e) {
- return;
- }
- int pivot = partition(array,s,e);
- //递归左边
- quick(array,0,pivot - 1);
- //递归右边
- quick(array,pivot + 1,e);
- }
- //挖坑法 ----> 找基准值(pivot)
- public int partition(int[] array, int left, int right) {
- int temp = array[left];
- while (left < right) {
- if (left < right&& array[right] >= temp) {
- right--;
- }
- array[left] = array[right];
- if (left < right && array[left] <= temp) {
- left++;
- }
- array[right] = array[left];
- }
- array[left] = temp;
- return left;
- }
快速排序的优化 :
如果是一组有序的数列(1,2,3,4,5,6,7,8) 在这种情况下我们去找基准每次都会是第一个数.
那么递归的话永远都是右边递归,这样也就会形成单分支的情况 时间复杂度就会变成O(n^2)
空间复杂度 : O(n) , 为了避免单分支的情况,我们可以在设标准值的时候去改变一下.三数取中法
: 去判断三个数 最左边的 中间的 最右边的 . 拿出这三个数的第二大值(也就是不要最大的值,也不要最小的值,就取中间的那个数), 然后让它与0下标去交换,然后再去找基准.
- public void quick(int[] array, int s, int e) {
- if (s >= e) {
- return;
- }
-
- //三数取中法 避免单分支的情况
- int mid = findMid(array,s,e);
- swap(array,s,mid);
-
- int pivot = partition(array,s,e);
- //递归左边
- quick(array,0,pivot - 1);
- //递归右边
- quick(array,pivot + 1,e);
- }
- //找到第二大值
- public int findMid(int[] array, int s, int e) {
- int mid = s + (e - s) / 2;
- if (array[s] < array[e]) {
- if (array[mid] > array[e]) {
- return e;
- } else if (array[mid] < array[s]) {
- return s;
- } else {
- return mid;
- }
- } else {
- if (array[mid] > array[s]) {
- return s;
- } else if (array[mid] < array[e]) {
- return e;
- } else {
- return mid;
- }
- }
- }
快速排序的再优化 :
如果数据有很多 : 假设有100000个数,那么一直递归下去,它会变成几乎有序的数组,那么我们就可以采用插入排序.
可以设一个阈值 : 当 s - e == 10时 我们就去让它去进行插入排序.(因为插入排序在越有序的数组下它的时间复杂度越低).
- public void quick(int[] array, int s, int e) {
- if (s >= e) {
- return;
- }
- if (s - e <= 15) {
- insertSort(array,s,e);
- return;
- }
- //三数取中法 避免单分支的情况
- int mid = findMid(array,s,e);
- swap(array,s,mid);
-
- int pivot = partition(array,s,e);
- //递归左边
- quick(array,0,pivot - 1);
- //递归右边
- quick(array,pivot + 1,e);
- }
-
- //为快速排序服务的直接插入排序
- public void insertSort(int[] array, int s, int e) {
- for (int i = s; i <= e; i++) {
- int temp = array[i];
- int j = i - 1;
- for (; j >= 0; j--) {
- if (array[j] > temp) {
- array[j + 1] = array[j];
- } else {
- array[j + 1] = temp;
- break;
- }
- }
- array[j + 1] = temp;
- }
- }
经过以上两种优化那么快速排序的速度只会更快!!!!!
快速排序的时间复杂度 : O(nlogn)
空间复杂度 : O(logn)
稳定性 : 不稳定
以上就是快速排序了!!!!!
- /**
- * 归并排序
- * 时间复杂度 : O(n*logn)
- * 空间复杂度 : O(n)
- * 稳定性 : 稳定
- * @param array
- */
- public void mergeSort(int[] array) {
- mergeSortFunc(array,0,array.length - 1);
- }
- public void mergeSortFunc(int[] array, int left, int right) {
- if (left >= right) {
- return;
- }
- int mid = left + (right - left) / 2;
- mergeSortFunc(array,left,mid);
- mergeSortFunc(array,mid + 1,right);
- merge(array,left,mid,right);
- }
- public void merge(int[] array, int start, int mid, int end) {
- int s1 = start;
- int s2 = mid + 1;
- int[] tmp = new int[end - start + 1];
- int k = 0;
- while (s1 <= mid && s2 <= end) {
- if (array[s1] > array[s2]) {
- tmp[k++] = array[s2++];
- } else {
- tmp[k++] = array[s1++];
- }
- }
- while (s1 <= mid) {
- tmp[k++] = array[s1++];
- }
- while (s2 <= end) {
- tmp[k++] = array[s2++];
- }
-
- for (int i = 0; i < tmp.length; i++) {
- array[start + i] = tmp[i];
- }
- }
归并排序的时间复杂度 : O(n*logn)
空间复杂度 : O(n)
稳定性 : 稳定
以上就是归并排序了!!!
到这里七大排序就全部结束了!
希望可以帮助到大家,如果什么疑问的话,可以私信我~~~~~~~
目录
排序 : 所谓排序就是使一串无序的数据进行排序后,变为递增或递减的数列.
稳定性 : 若有一组数据 : (为了看出效果,我加了一个标识符 a 与 b)编辑
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。