近最研究元素排序,稍微总结一下,以后继承补充:
近最决议天每学点数据结构与算法,写客博来促督自己继承学习~
以下的每个排序的写法格式基本按照先分析基本想思,再描述详细程过,最后是详细码代。关于复杂度等问题后续更新。若有写的不谨严的地方,迎欢指出,互相流交。
希尔排序
基本想思:将一组数据按照定一的步长组分,停止直接入插排序,然后再缩小步长,再排序,直到步长为1,再停止一次排序,就到得了有序列序。
以面下一组数据为例:
{ 8, 19, 2, 5, 7, 10, 12, 16, 18, 20 }
根据wiki百科,我选择了一种取选步长的式方,即初始取n/2(n为数据的长度)作为步长,其后将步长减半,直至步长减为1.其他步长取选方法可以见参wiki百科。
详细程过:
详细码代:
/** * 希尔排序 * * 步长选择size/2为并且对步长取半直到步长到达 1 * * @param d * 要排序的数组 */ public static void shellSort(int[] d) { int size = d.length; int tmp; for (int i = size / 2; i > 0; i /= 2) { for (int j = i; j < size; j++) { int k = j; Boolean flag = false; while (k - i >= 0) {// 有优化的空间,如果两个数较比后没有停止交换,应可以直接跳出循环 if (d[k] < d[k - i]) { tmp = d[k]; d[k] = d[k - i]; d[k - i] = tmp; flag = true; } if (flag) break; k -= i; } } } }
堆排序
首先须要道知的知识,二叉树,已知父点节i,左孩子点节(2 * i + 1),右孩子点节(2 * i + 2);若已知孩子点节,父点节为((i - 1) / 2)。
小最堆性子是,父点节的值的小大要求小于即是右左孩子点节的值。
建立小最堆,到得的是减递列序;反之,建立最大堆,到得递增列序。
基本想思:建立一个小最堆(或最大堆,本文中均以小最堆为例)。根据小最堆性子可以道知,根点节元素是小最的元素,因此每次删除这个点节,停止小最堆的调整,始终重复这个程过,直至仅剩最后一个元素,排序成完。
以面下一组数据为例:
{ 8, 9, 2, 5, 7, 10, 12, 16, 18, 20 }
基本程过:
建立小最堆
根据片图示指的次序,一个一个个将数组中的元素入加到堆中,并停止调整,终最到得小最堆。
至此略省几步,将数据一个个入加便可。终最到得的小最堆:
建完小最堆后之,可以清晰瞥见小最堆的性子,根点节的值定一小于即是右左孩子点节的值。接下来,要做的是将根点节删除,然后将最后一个元素的值赋给根点节,然后停止一个调整。这个程过的图就一不一画了,仅画第一步,接下来的操纵相似。
到得一个新的小最堆:
详细码代:
/** * 堆排序 * * 因为用使的是小最堆,所以到得的列序是减递列序;如果要递增列序则须要用使最大堆 * * @param d * 要排序的数组 * @param n * 数组的长度 */ public static void heapSort(int[] d, int n) { int tmp; for (int i = n - 1; i > 0; i--) { tmp = d[i]; d[i] = d[0]; d[0] = tmp; heapMakeDown(d, 0, i); } } /** * 建立小最堆 * * @param d * 要建堆的数组 * @param n * 数组的长度 */ public static void makeMinHeap(int[] d, int n) { for (int i = n / 2 - 1; i >= 0; i--) { heapMakeDown(d, i, n); } } /** * 从点节i开始停止调整 * * @param d * 要调整的数组 * @param i * 从点节i开始 * @param n * 数组的长度 */ public static void heapMakeDown(int[] d, int i, int n) { int j, tmp; tmp = d[i]; j = 2 * i + 1; while (j < n) { if (j + 1 < n && d[j + 1] < d[j]) // 寻觅右左孩子中小的那一个 j++; if (tmp <= d[j])// 父点节的值比右左孩子中小的那个还小,则不须要调整 break; d[i] = d[j]; i = j; j = 2 * i + 1; } d[i] = tmp; }
归并排序
基本想思:归并排序用了分治的想思。将两个有序的列序,合并为一个列序。只要将两个列序的第一个值较比,将较小的元素添加到合并的列序,删除这个较小的元素,再继承较比。直到某一个列序为空,以可就将另一个列序的元素添加到合并的列序。
详细码代:
/** * 合并d[first]-->d[mid],d[mid+1]-->d[last] * * @param d * 要排序的数组 * @param first * 始起标下 * @param mid * 旁边标下 * @param last * 结束标下 * @param tmp * 时临数组 */ public static void merge(int[] d, int first, int mid, int last, int[] tmp) { int i = first, j = mid + 1; int index = 0; while (i <= mid && j <= last) { // 从中取选小的那一个入加新的数组 if (d[i] < d[j]) { tmp[index++] = d[i++]; } else { tmp[index++] = d[j++]; } } // 入加d[first]-->d[mid],d[mid+1]-->d[last]中长度更长的数组的残余元素 while (i <= mid) { tmp[index++] = d[i++]; } while (j <= last) { tmp[index++] = d[j++]; } for (i = 0; i < index; i++) { d[first + i] = tmp[i]; } } /** * 归并排序(递归) * * @param d * 要排序的数组 * @param first * 始起标下 * @param last * 结束标下 * @param tmp * 时临数组,用来放存排好序的元素 */ public static void mergeSort(int[] d, int first, int last, int[] tmp) { if (first < last) { int mid = (first + last) / 2; mergeSort(d, first, mid, tmp); mergeSort(d, mid + 1, last, tmp); merge(d, first, mid, last, tmp); } }
快速排序
基本想思:快速排序用使了“分治法”。先从一个列序中找到一个基准元素,将列序分为两部份,左部份元素值都小于即是基准元素;右部份元素值都大于基准元素。递归的把右左两部份列序继承此操纵,直至列序元素为1.
以面下一组数据为例:
{ 8, 9, 2, 5, 7, 10, 12, 16, 18, 20 }
详细程过:
这一组数据也可以明说快速排序是不稳定的。在列序大多数都有序的情况下,选择快排不定一是最好的选择。
详细码代:
/** * 快速排序 * * @param d * 要排序的数组 * @param first * 开始标下 * @param last * 结束标下 */ public static void quickSort(int[] d, int first, int last) { if (first >= last) return; int i = first, j = last; int pivot = d[i];// 取选第一个元素作为基准元素 while (i < j) { while (i < j && d[j] > pivot) { // 从右往左找比基准元素小的元素 j--; } if (i < j) { d[i++] = d[j]; } while (i < j && d[i] <= pivot) { // 从左往右找比基准元素大的元素 i++; } if (i < j) { d[j--] = d[i]; } } d[i] = pivot;// 这时i = j,将基准元素放在这个位置 quickSort(d, first, i - 1); quickSort(d, i + 1, last); }
选择排序
基本想思:选择排序就是将列序中未排序的部份中的小最元素,放入到列序的已排序部份的首位;接着在未排序部份继承寻觅小最元素,放入已排序部份的末端,直到全部元素排序毕完。
以下的每个排序中用使的数据都同相。
详细程过:
详细码代:
/** * 选择排序 * * @param d * 要排序的数组 * @param n * 数组的长度 */ public static void selectSort(int[] d, int n) { int tmp; Boolean flag = false; for (int i = 0; i < n - 1; i++) { for (int j = i + 1; j < n; j++) { // 记着索引与直接交换的别区? if (d[i] > d[j]) { tmp = d[i]; d[i] = d[j]; d[j] = tmp; flag = true; } flag = false; } if (flag) break; } }
入插排序
基本想思:入插排序是对每个未排序元素,在已排序列序中从后往前查找,发明适合的位置将此元素入插到已排序列序,直到描扫完全部的未排序元素。
详细程过:
详细码代:
/** * 入插排序 * * @param d * 要排序的数组 * @param n * 数组的长度 */ public static void insertionSort(int[] d, int n) { int tmp; for (int i = 1; i < n; i++) { tmp = d[i]; int j = i - 1; while (j >= 0 && d[j] > tmp) { d[j + 1] = d[j]; j--; } d[j + 1] = tmp; } }
冒泡排序
基本想思:较比相邻的两个元素,如果前一个元素比后一个元素大,则交换;记录下每次交换时的标下,下一次交换的时候仅须要从开始的元素到上轮交换的最后一个标下便可,优化了简略冒泡排序。
详细程过:
详细码代:
/** * 冒泡排序 * * @param d * 要排序的数组 * @param n * 数组长度 */ public static void bubbleSort(int[] d, int n) { int flag = n; int j, tmp; while (flag > 0) { j = flag; flag = 0; for (int i = 1; i < j; i++) { if (d[i] < d[i - 1]) { tmp = d[i - 1]; d[i - 1] = d[i]; d[i] = tmp; flag = i;// 记着有变改的标下,下一次只须要在0-->flag之间排序便可 } } } }
文章结束给大家分享下程序员的一些笑话语录:
那是习惯决定的,一直保持一个习惯是不好的!IE6的用户不习惯多标签,但是最终肯定还是得转到多标签的浏览器。历史(软件UI)的进步(改善)不是以个人意志(习惯)为转移的!