Skip to content

Commit 76537f2

Browse files
WuYifanXazl397985856
authored andcommittedJun 21, 2019
feat: 每日一题 2019-06-11 (azl397985856#39)
* [Daily] * add daily answer for 2019-06-14 * [Daily] * update for 2019-06-11 daily project * [Daily] * rename for 2019-06-11 daily project
1 parent c08de1a commit 76537f2

File tree

3 files changed

+198
-5
lines changed

3 files changed

+198
-5
lines changed
 

‎daily/2019-06-11.md

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
## 每日一题 - 重复数据排序优化
2+
3+
### 信息卡片
4+
5+
- 时间:2019-06-11
6+
- tag:`Quike Sort`
7+
8+
### 题目描述
9+
10+
```
11+
如果一个数组含有大量重复元素,我们应该选择什么样的排序方法,背后的理论依据是什么”?
12+
```
13+
14+
15+
### 参考答案
16+
17+
取决于数据分布如何
18+
19+
1. 如果数据的总类很少, 而且每个都有大量重复的元素, 那么使用计数排序, 那么这个时间复杂度能够达到O(N).
20+
```java
21+
public class CountSort {
22+
public int[] countSort(int[] array) {
23+
int max = array[0];
24+
for(int i=1; i<array.length; i++) {
25+
if(array[i]>max) {
26+
max = array[i];
27+
}
28+
}
29+
//创建计数数组
30+
int[] countArray = new int[max+1];
31+
for(int i=0; i<array.length; i++) {
32+
countArray[array[i]]++;
33+
}
34+
int index = 0;
35+
//创建返回数组
36+
int[] sortArray = new int[array.length];
37+
for(int i=0; i<countArray.length; i++) {
38+
for(int j=0; j<countArray[i]; j++) {
39+
sortArray[index++] = i;
40+
}
41+
}
42+
return sortArray;
43+
}
44+
}
45+
```
46+
2. 如果数据没有明显的规律, 可以考虑快排. 其性能与pivot的选择有关. 如果每次partition过程中的pivot选择能够较好的平分数组, 那么快排的速度能够达到O(NlogN). 因此再选择pivot时候, 可以选择数组中几个中间大小的数字. 此外, 对于重复数量大的数据, 可以选择三路快排来排序. 最后, 因为再数据近乎有序的时候, 插入排序的速度可以达到O(N), 所以在数据近乎有序的时候, 我们使用插入排序来优化排序过程.
47+
48+
```java
49+
private class QuickSort{
50+
51+
// 快排转化成为插入排序的阈值
52+
private static final int INSERTION_SORT_THRESHOLD = 47;
53+
54+
public void QuickSort(int[] a) {
55+
if (a.length > 0) {
56+
quickSort(a, 0, a.length - 1);
57+
}
58+
}
59+
60+
private void swap(int[] arr, int a, int b) {
61+
int temp = arr[a];
62+
arr[a] = arr[b];
63+
arr[b] = temp;
64+
}
65+
66+
private int choosePivotMedianOfThree(int[] a, int l, int r) {
67+
int mid = 0;
68+
if ((r-l+1) % 2 == 0) {
69+
mid = l + (r-l+1)/2 - 1;
70+
} else {
71+
mid = l + (r-l+1)/2;
72+
}
73+
74+
// 只需要找出中位数即可,不需要交换
75+
if (((a[l]-a[mid]) * (a[l]-a[r])) <= 0) {
76+
return l;
77+
} else if (((a[mid]-a[l]) * (a[mid]-a[r])) <= 0) {
78+
return mid;
79+
} else {
80+
return r;
81+
}
82+
}
83+
84+
private void quickSort(int[] a, int left, int right) {
85+
if (right <= left)
86+
return;
87+
88+
// 在数据近乎有序的时候, 插入排序的性能近乎于O(N)
89+
if(right - left <= INSERTION_SORT_THRESHOLD) {
90+
insertSort(a, left, right)
91+
}
92+
93+
/*
94+
* 工作指针
95+
* p指向序列左边等于pivot元素的位置
96+
* q指向序列右边等于Pivot元素的位置
97+
* i指向从左向右扫面时的元素
98+
* j指向从右向左扫描时的元素
99+
*/
100+
int p, q, i, j;
101+
int pivot;// 锚点
102+
i = p = left;
103+
j = q = right - 1;
104+
105+
106+
/*
107+
* 每次总是取序列最右边/最优和最中间的元素的大小中间值为锚点
108+
*/
109+
pivot = choosePivotMedianOfThree(a, left, right);
110+
111+
//始终将第一个元素作为pivot, 若不是, 则与之交换
112+
if (pivot != left) {
113+
swap(a, pivot, left);
114+
}
115+
pivot = a[right];
116+
117+
while (true) {
118+
/*
119+
* 工作指针i从右向左不断扫描,找小于或者等于锚点元素的元素
120+
*/
121+
while (i < right && a[i] <= pivot) {
122+
/*
123+
* 找到与锚点元素相等的元素将其交换到p所指示的位置
124+
*/
125+
if (a[i] == pivot) {
126+
swap(a, i, p);
127+
p++;
128+
}
129+
i++;
130+
}
131+
/*
132+
* 工作指针j从左向右不断扫描,找大于或者等于锚点元素的元素
133+
*/
134+
while (left <= j && a[j] >= pivot) {
135+
/*
136+
* 找到与锚点元素相等的元素将其交换到q所指示的位置
137+
*/
138+
if (a[j] == pivot) {
139+
swap(a, j, q);
140+
q--;
141+
}
142+
j--;
143+
}
144+
/*
145+
* 如果两个工作指针i j相遇则一趟遍历结束
146+
*/
147+
if (i >= j)
148+
break;
149+
150+
/*
151+
* 将左边大于pivot的元素与右边小于pivot元素进行交换
152+
*/
153+
swap(a, i, j);
154+
i++;
155+
j--;
156+
}
157+
/*
158+
* 因为工作指针i指向的是当前需要处理元素的下一个元素
159+
* 故而需要退回到当前元素的实际位置,然后将等于pivot元素交换到序列中间
160+
*/
161+
i--;
162+
p--;
163+
while (p >= left) {
164+
swap(a, i, p);
165+
i--;
166+
p--;
167+
}
168+
/*
169+
* 因为工作指针j指向的是当前需要处理元素的上一个元素
170+
* 故而需要退回到当前元素的实际位置,然后将等于pivot元素交换到序列中间
171+
*/
172+
j++;
173+
q++;
174+
while (q <= right) {
175+
swap(a, j, q);
176+
j++;
177+
q++;
178+
}
179+
180+
/*
181+
* 递归遍历左右子序列
182+
*/
183+
quickSort(a, left, i);
184+
quickSort(a, j, right);
185+
}
186+
}
187+
```
188+

‎daily/2019-06-14.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,4 @@ var flatten = function(root) {
155155
}
156156
157157
158-
```
158+
```

‎daily/README.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,20 @@ tag: `Tree`
4141

4242
时间: 2019-06-10
4343

44-
4544
### [三门问题](./2019-06-13.md)
4645

47-
tag: `Probability Theory`
46+
tag: `Probability Theory`
4847

4948
时间: 2019-06-13
5049

50+
### [重复数据排序优化](./2019-06-11.md)
51+
52+
tag: `Sort` `Quick Sort`
53+
54+
时间: 2019-06-11
55+
5156
### [114.flatten-binary-tree-to-linked-list](./2019-06-14.md)
5257

53-
tag: `tree`
58+
tag: `tree`
5459

55-
时间: 2019-06-14
60+
时间: 2019-06-14

0 commit comments

Comments
 (0)