@@ -10,6 +10,7 @@ public class Sort {
1010 * 选择排序,每一轮排序,选择数组中数字最小的那一个放到指定的位置上。
1111 * 时间复杂度o(n^2),无论数组顺序如何都要选择一个最小的值,因为数组的是否有序,不影响时间复杂度
1212 * 空间复杂度o(1)
13+ *
1314 * @param nums
1415 */
1516 public void chooseSort (int [] nums ) {
@@ -32,43 +33,45 @@ public void chooseSort(int[] nums) {
3233 * 直接插入排序,每一轮排序,都是在i坐标之前,包括i坐标的序列是有序的,但是并不是最终的排序位置。
3334 * 时间复杂度o(n^2),对于第二重循环,只会在非有序的环境下才会执行每个元素后移,因此针对有序的数组,时间复杂度最好的情况是o(N)。
3435 * 空间复杂度o(1)
36+ *
3537 * @param nums
3638 */
3739 public void insertDirectlySort (int [] nums ) {
3840 int length = nums .length ;
3941 for (int i = 1 ; i < length ; i ++) {
40- for (int j = i ; j > 0 ; j --) {
41- if (nums [j ] < nums [j - 1 ]) {
42- int tmp = nums [j - 1 ];
43- nums [j - 1 ] = nums [j ];
44- nums [j ] = tmp ;
45- }
46- }
42+ for (int j = i ; j > 0 ; j --) {
43+ if (nums [j ] < nums [j - 1 ]) {
44+ int tmp = nums [j - 1 ];
45+ nums [j - 1 ] = nums [j ];
46+ nums [j ] = tmp ;
47+ }
48+ }
4749 }
4850 }
4951
5052 /**
5153 * 折半插入排序,针对直接排序而言,每一个要插入的元素都是插入在有序的数组中,因此,只需要查找到插入的位置即可,查找的方式利用二分查找
5254 * 时间复杂度和直接插入是一样的,只是快在了查找的过程中,还是o(N^2),最好的环境下是o(N)
5355 * 空间复杂度还是o(1)
56+ *
5457 * @param nums
5558 */
5659 public void insertBinarySort (int [] nums ) {
5760 int length = nums .length ;
58- for (int i = 1 ; i < length ;i ++) {
61+ for (int i = 1 ; i < length ; i ++) {
5962 int tmp = nums [i ];
6063 int low = 0 ;
6164 int high = i - 1 ;
6265 while (low <= high ) {
6366 int mid = (low + high ) / 2 ;
6467 if (tmp < nums [mid ]) {
6568 high = mid - 1 ;
66- }else {
69+ } else {
6770 low = mid + 1 ;
6871 }
6972 }
7073
71- for (int j = i ; j >= low + 1 ;j --) {
74+ for (int j = i ; j >= low + 1 ; j --) {
7275 nums [j ] = nums [j - 1 ];
7376 }
7477 nums [low ] = tmp ;
@@ -80,16 +83,17 @@ public void insertBinarySort(int[] nums) {
8083 * 这种实现是按照算法定义的,但是效率是最低的
8184 * 时间复杂度o(n^2)
8285 * 空间复杂度o(1)
86+ *
8387 * @param nums
8488 */
8589 public void bubbleSort1 (int [] nums ) {
8690 int length = nums .length ;
87- for (int i = 1 ; i < length ;i ++) {
88- for (int j = 0 ; j < length - i ;j ++) {
91+ for (int i = 1 ; i < length ; i ++) {
92+ for (int j = 0 ; j < length - i ; j ++) {
8993 if (nums [j ] > nums [j + 1 ]) {
9094 int tmp = nums [j ];
9195 nums [j ] = nums [j + 1 ];
92- nums [j + 1 ] = tmp ;
96+ nums [j + 1 ] = tmp ;
9397 }
9498 }
9599 }
@@ -98,27 +102,30 @@ public void bubbleSort1(int[] nums) {
98102 /**
99103 * 冒泡排序,高效率实现,因为只需要用一个flag变量来记录本次的排序,是否修改
100104 * 如果没有修改,说明已经有序
105+ *
101106 * @param nums
102107 */
103108 public void bubbleSort2 (int [] nums ) {
104109 int length = nums .length ;
105110 boolean flag = true ;
106111 while (flag ) {
107112 flag = false ;
108- for (int j = 0 ; j < length - 1 ;j ++) {
113+ for (int j = 0 ; j < length - 1 ; j ++) {
109114 if (nums [j ] > nums [j + 1 ]) {
110115 int tmp = nums [j ];
111116 nums [j ] = nums [j + 1 ];
112117 nums [j + 1 ] = tmp ;
113118 flag = true ;
114119 }
115120 }
116- length -- ;
121+ length -- ;
117122 }
118123 }
119124
120125 /**
121126 * 快速排序,选定一个切分元素,每一轮排序后,都保证切分元素之前的元素都小于切分元素,切分元素之后的元素都大于切分元素
127+ * 时间复杂度o(NlgN)
128+ * 空间复杂度o(lgN)
122129 *
123130 * @param nums
124131 */
@@ -130,6 +137,7 @@ public void quickSort(int[] nums) {
130137
131138 /**
132139 * 快速排序的递归实现
140+ *
133141 * @param nums
134142 * @param low
135143 * @param high
@@ -143,6 +151,7 @@ public void sort(int[] nums, int low, int high) {
143151
144152 /**
145153 * 快速排序的辅助方法,来对排序的数组,进行切分,
154+ *
146155 * @param nums
147156 * @param low
148157 * @param high
@@ -154,7 +163,7 @@ public int partition(int[] nums, int low, int high) {
154163 int x = nums [i ];
155164 while (i < j ) {
156165 //从右向左找到nums[j]小于x的元素
157- while (i < j && nums [j ] > x ) j -- ;
166+ while (i < j && nums [j ] > x ) j --;
158167 if (i < j ) {
159168 nums [i ] = nums [j ];
160169 i ++;
@@ -171,6 +180,75 @@ public int partition(int[] nums, int low, int high) {
171180 return i ;
172181 }
173182
174-
183+
184+ /**
185+ * 堆排序,建立一个小顶堆,小顶堆满足父节点比两个子节点的值要小
186+ * 堆的性质满足:1. 只能在堆顶删除元素
187+ * 2. 只能在堆的最后一位存元素。
188+ * 3. 堆的存储利用数组,满足i节点是父节点,则子节点是2 * i+ 1,2 * i + 2
189+ * 4. 堆的两种建方法,第一种是从上到下,@see sink(),第二种是从下到上 @see swim
190+ * 5. 堆排序是指在弄好的堆中,输出第一个元素,然后将最后一个元素与第一个元素互换,换后调用sink,找到自己的位置后,在重复这个步骤,就输出一个有序的堆
191+ * 6. 如果要生序就需要大顶堆,要降序就需要小顶堆。
192+ * 时间复杂度:o(NlgN)
193+ * 空间复杂度: o(1)
194+ * 这是小顶堆的排序,所以nums数组最后是降序的
195+ * @param nums
196+ */
197+ public void heapSort (int [] nums ) {
198+ int length = nums .length ;
199+ for (int i = 0 ; i < length ; i ++) {
200+ swim (nums , i );
201+ }
202+ while (length > 0 ) {
203+ int temp = nums [0 ];
204+ nums [0 ] = nums [length - 1 ];
205+ nums [length - 1 ] = temp ;
206+ length --;
207+ sink (nums , 0 , length );
208+ }
209+ }
210+
211+ /**
212+ * 将i放入对堆中,i的父节点是(i - 1)/ 2,父节点的值是小于他的两个子节点的
213+ * i节点放入后,要向上移动,如果父节点比i节点的值大,则i节点要继续上移。
214+ *
215+ * @param nums
216+ * @param i
217+ */
218+ private void swim (int nums [], int i ) {
219+ while (i > 0 ) {
220+ int father = (i - 1 ) / 2 ;
221+ if (nums [father ] > nums [i ]) {
222+ int temp = nums [father ];
223+ nums [father ] = nums [i ];
224+ nums [i ] = temp ;
225+ }
226+ i = father ;
227+ }
228+ }
229+
230+
231+ /**
232+ * 从i节点由上到下开始调整,i节点的子节点为2*i + 1, 2 * i + 2
233+ * i节点要向下移动,直到满足i节点小于两个子节点
234+ *
235+ * @param nums nums[] 数组
236+ * @param i i节点
237+ */
238+ public void sink (int nums [], int i ,int n ) {
239+ int son = 2 * i + 1 ;
240+ while (son <= n - 1 ) {
241+ if (son < n - 1 && nums [son ] > nums [son + 1 ]) son ++;
242+ if (nums [i ] > nums [son ]) {
243+ int temp = nums [i ];
244+ nums [i ] = nums [son ];
245+ nums [son ] = temp ;
246+ i = son ;
247+ } else {
248+ break ;
249+ }
250+ }
251+ }
252+
175253
176254}
0 commit comments