int A[] = {3,2,1,2,3,2,1,3,1,2,3};
如何高效地对这个数组进行排序?这是面试需要的,只需要提供一个伪代码。
int A[] = {3,2,1,2,3,2,1,3,1,2,3};
如何高效地对这个数组进行排序?看起来最有前途的排序方法似乎是计数排序。建议查看这个讲座,由Richard Buckland主讲,特别是从15:20开始的部分。
类比于计数排序,但更好的方法是创建一个表示域的数组,将其所有元素初始化为0,然后遍历您的数组并计算这些值的数量。一旦您知道了域值的计数,就可以相应地重写数组的值。这种算法的复杂度为O(n)。
这是C ++代码,其行为与我描述的相同。尽管其复杂度实际上为O(2n):
int A[] = {3,2,1,2,3,2,1,3,1,2,3};
int domain[4] = {0};
// count occurrences of domain values - O(n):
int size = sizeof(A) / sizeof(int);
for (int i = 0; i < size; ++i)
domain[A[i]]++;
// rewrite values of the array A accordingly - O(n):
for (int k = 0, i = 1; i < 4; ++i)
for (int j = 0; j < domain[i]; ++j)
A[k++] = i;
std::map
存储域值-出现次数对的C++代码:int A[] = {2000,10000,7,10000,10000,2000,10000,7,7,10000};
std::map<int, int> domain;
// count occurrences of domain values:
int size = sizeof(A) / sizeof(int);
for (int i = 0; i < size; ++i)
{
std::map<int, int>::iterator keyItr = domain.lower_bound(A[i]);
if (keyItr != domain.end() && !domain.key_comp()(A[i], keyItr->first))
keyItr->second++; // next occurrence
else
domain.insert(keyItr, std::pair<int,int>(A[i],1)); // first occurrence
}
// rewrite values of the array A accordingly:
int k = 0;
for (auto i = domain.begin(); i != domain.end(); ++i)
for (int j = 0; j < i->second; ++j)
A[k++] = i->first;
如果有更高效使用std::map
的方法,请告诉我。
计算每个数字的出现次数,并根据它们的数量创建新数组...时间复杂度为O(n)。
int counts[3] = {0,0,0};
for(int a in A)
counts[a-1]++;
for(int i = 0; i < counts[0]; i++)
A[i] = 1;
for(int i = counts[0]; i < counts[0] + counts[1]; i++)
A[i] = 2;
for(int i = counts[0] + counts[1]; i < counts[0] + counts[1] + counts[2]; i++)
A[i] = 3;
正如Robert所提到的,BasketSort(或BucketSort)是这种情况下最好的选择。
我还想补充另一个算法(实际上与busket sort非常相似):
[伪代码采用Java风格]
创建一个HashMap<Integer, Interger> map
并循环遍历你的数组:
for (Integer i : array) {
Integer value = map.get(i);
if (value == null) {
map.put(i, 1);
} else {
map.put(i, value + 1);
}
}
这是基于@ElYusubov的Groovy解决方案,但不是将Bucket(5)推到开头和Bucket(15)推到结尾,而是使用筛选,使5向开头移动,15向结尾移动。
每当我们从结尾交换桶时,我们会将end减1,不会增加当前计数器,因为我们需要再次检查该元素。
array = [15,5,10,5,10,10,15,5,15,10,5]
def swapBucket(int a, int b) {
if (a == b) return;
array[a] = array[a] + array[b]
array[b] = array[a] - array[b]
array[a] = array[a] - array[b]
}
def getBucketValue(int a) {
return array[a];
}
def start = 0, end = array.size() -1, counter = 0;
// we can probably do away with this start,end but it helps when already sorted.
// start - first bucket from left which is not 5
while (start < end) {
if (getBucketValue(start) != 5) break;
start++;
}
// end - first bucket from right whichis not 15
while (end > start) {
if (getBucketValue(end) != 15) break;
end--;
}
// already sorted when end = 1 { 1...size-1 are Buck(15) } or start = end-1
for (counter = start; counter < end;) {
def value = getBucketValue(counter)
if (value == 5) { swapBucket(start, counter); start++; counter++;}
else if (value == 15) { swapBucket(end, counter); end--; } // do not inc counter
else { counter++; }
}
for (key in array) { print " ${key} " }
可以非常容易地使用以下方式进行-->
荷兰国旗算法 http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Flag/
不要使用1、2、3,而是将其视为0、1、2
仅供娱乐,以下是如何实现“将值推送到远端”的方法,正如ElYusubub所建议的:
sort(array) {
a = 0
b = array.length
# a is the first item which isn't a 1
while array[a] == 1
a++
# b is the last item which isn't a 3
while array[b] == 3
b--
# go over all the items from the first non-1 to the last non-3
for (i = a; i <= b; i++)
# the while loop is because the swap could result in a 3 or a 1
while array[i] != 2
if array[i] == 1
swap(i, a)
while array[a] == 1
a++
else # array[i] == 3
swap(i, b)
while array[b] == 3
b--
这可能是一个最优的解决方案。我不确定。