您的位置:首页 > 其它

OJ中常用的功能函数(顺序数)

2014-08-15 00:22 211 查看
1.找第 i 顺序数

最佳算法的最坏、平均时间复杂度为:O(n),但是理论较难且实现起来也很复杂,故不介绍。

快选择算法的平均复杂度为O(n)(虽然最坏为O(n^2),但是发生概率极小),并且实现简单,所以用起来很方便。

思想:借用归并排序的Partition函数,分界元素是第几大已知,并且左边是小的右边是大的,因此将问题分而治之。

int Partition(vector<int> &v, int p, int r)
{
int x = v[r];//选取最后一个元素作为参照
int i = p - 1, j = p;
for(; j < r; j++)
{
if(v[j] <= x)
{
i++;
swap(v[j], v[i]);
}
}
swap(v[r], v[i+1]);
return i+1;
}

int QuickSelect(vector<int> &v, int p, int r, int m)
{
int q, result;
q = Partition(v, p, r);
if( q == m - 1)//因为数组是从0开始的
return v[q];
else if(m < q)
result = QuickSelect(v, p, q - 1, m);
else
result = QuickSelect(v, q + 1, r, m);
return result;
}

2.堆排序

主要是为了在找最大k个数中需要用到堆得建立于调整,所以在此介绍堆排序。

//调整最大堆,root为要调整的子树的根,n为当前堆大小
void MaxHeapify(vector<int> &v, int n, int root)
{
int lchild = 2 * (root + 1) - 1, rchild = 2 * (root + 1), largest; //此处数组从下标0开始,不需要从1开始
if(lchild < n && v[root] < v[lchild])
largest = lchild;
else
largest = root;
if(rchild < n && v[largest] < v[rchild])
largest = rchild;
if(largest != root) //根、左儿子和右儿子三者之间的最大者 和 根互换即可
{
swap(v[largest], v[root]);
MaxHeapify(v, n, largest);
}
}

//建最大堆
void BuildMaxHeap(vector<int> &v, int root)
{
int lchild = 2 * (root + 1) - 1, rchild = 2 * (root + 1);
if(lchild < v.size())
BuildMaxHeap(v, lchild); //建左子树
if(rchild < v.size())
BuildMaxHeap(v, rchild); //建右子树
MaxHeapify(v, v.size(), root); //调整最大堆
}

//堆排序
void HeapSort(vector<int> &v)
{
BuildMaxHeap(v, 0); //建堆
int n = v.size();
while(n--)
{
swap(v[0], v
); //将最大元素移到最后
MaxHeapify(v, n, 0); //将未排序部分调整为最大堆
}
}


3.找最小的k个数

(1)思路1:基于堆的,建k个元素的最大堆,然后对剩余的元素依次与根比较,若是比根小就替换根,然后进行堆调整,否则什么都不做,最后堆里的元素就是那最小的k个数,时间复杂度为O(nlogk)。

(2)思路2:建n个元素的最小堆,然后输出k次最小值,比较次数是2n + 2klgn,时间复杂度为O(n + klogn)。缺点是空间复杂度较高,需要O(n)。

(3)思路3:利用锦标赛树。比较次数可以为n + (k - 1)[lgn] - k。在此就不介绍了。

(4)思路1的代码:

//建最大堆,将前n个元素建堆
void BuildMaxHeap(vector<int> &v, int n, int root)
{
int lchild = 2 * (root + 1) - 1, rchild = 2 * (root + 1);
if(lchild < n)
BuildMaxHeap(v, n, lchild);
if(rchild < n)
BuildMaxHeap(v, n, rchild);
MaxHeapify(v, n, root);
}

void SelectKMin(vector<int> &v, int k) //v的前k个元素就是结果
{
BuildMaxHeap(v, k, 0);
int i;
for(i = k; i < v.size(); i++)
{
if(v[i] < v[0])
{
swap(v[0], v[i]);
MaxHeapify(v, k, 0);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 顺序数