【算法作业】top-k和CubeSort

问题描述

  1. 在不同应用领域,经常涉及到top-K的问题,请给出不同策略在一系列数中返回Top-K元素,并分析你的策略。

  2. 调研学习排序算法CubeSort,体会分治思想的使用。

解题思路

T1

  1. 方法一(直接排序法):

将整个数组排序,然后取前K个元素作为结果。常见的排序算法包括快速排序、归并排序等。

  • 优点: 简单直观,易于实现。
  • 缺点: 时间复杂度较高,通常为 O(nlogn),不适用于大规模数据集。并且,如果只需要前K个元素而不需要对整个数组排序,则效率低下。
  1. 方法二(堆/优先队列):

使用堆数据结构来解决Top-K元素问题,通常是使用小根堆或大根堆。

  • 优点: 时间复杂度为 O(nlogk),适用于大规模数据集,只需维护大小为K的堆,节省了排序整个数组的开销。
  • 缺点: 实现稍微复杂一些,需要理解堆数据结构的性质和操作。
  1. 方法三(快速选择):

这是一种改进的快速排序算法,用于查找未排序数组中的第K个最小元素。

  • 优点: 平均时间复杂度为 O(n),在实践中通常比堆更快。
  • 缺点: 最坏情况下时间复杂度为 O(n^2),但是通过一些优化策略可以将最坏情况的概率降低到很小。

T2

CubeSort 是一种分治排序算法,其基本思想是将待排序数组划分为多个立方体(cubes),然后分别对每个立方体进行排序,最后将这些有序的立方体合并成一个有序数组。下面是 CubeSort 算法的基本步骤:

  1. 划分立方体: 将待排序的数组划分为多个立方体,每个立方体包含固定数量的元素。立方体的数量可以根据实际情况调整,通常选择的大小与计算机内存大小和处理器缓存大小相关。

  2. 对每个立方体排序: 对每个立方体中的元素进行排序。可以选择任何一种排序算法来完成这个任务,通常选择效率较高的排序算法,比如快速排序或归并排序。

  3. 合并有序立方体: 将排序好的立方体按照一定规则合并,形成整体有序的数组。这一步可以使用归并操作来实现,将每个立方体的顶部元素依次放入一个优先队列(或堆)中,并逐步取出构建有序序列。

CubeSort 算法的时间复杂度取决于三个步骤:划分立方体、排序每个立方体以及合并有序立方体。

  1. 划分立方体: 划分立方体的时间复杂度取决于数组的大小和立方体的大小。假设数组大小为 n,立方体的大小为 m,则划分立方体的时间复杂度为 O(n/m)。

  2. 排序每个立方体: 对每个立方体进行排序的时间复杂度取决于所选的排序算法。通常情况下,可以选择效率较高的排序算法,比如快速排序或归并排序。假设所选的排序算法时间复杂度为 O(m log m)。

  3. 合并有序立方体: 合并有序立方体的时间复杂度取决于数组的大小和立方体的数量。假设立方体数量为 k,则合并有序立方体的时间复杂度为 O(n log k)。

综合考虑以上三个步骤,CubeSort 算法的总体时间复杂度为:

O ( n m + m log ⁡ m + n log ⁡ k ) O\left(\frac{n}{m} + m \log m + n \log k\right) O(mn+mlogm+nlogk)

其中,n 表示数组的大小,m 表示立方体的大小,k 表示立方体的数量。立方体的大小和数量可以根据实际情况进行调整,以平衡算法的时间复杂度和空间复杂度。

完整代码

T1

  1. 方法一:
#include<iostream>
#include<algorithm>
using namespace std;

bool cmp(int a,int b)      
{                         
	return a > b;            
}                          
                      
int main()
{
	int n,a[100];
    cout<<"请输入数组大小:";
    cin>>n;
    cout<<"请输入数组:";
    for(int i=1;i<=n;i++){
    	int x;
    	cin>>a[i];
	}
    cout<<"请输入k:";
    int k;
    cin>>k;
	sort(a + 1, a + 1 + n, cmp);
	
	cout << "Top-k: " << a[k];

}

运行结果

请输入数组大小:5
请输入数组:2 4 1 5 3
请输入k:2
Top-k: 4
  1. 方法二:
#include<iostream>
#include<queue>
using namespace std;

int main() {
    // 创建一个最小堆优先队列,存储整数,找topk大的数 
    priority_queue<int, vector<int>, greater<int> > pq;

    int n;
    cout<<"请输入数组大小:";
    cin>>n;
    cout<<"请输入k:";
    int k;
    cin>>k;
    cout<<"请输入数组:";
    //这里建堆只用建k个,时间复杂度为O(klogk) 
    for(int i=1;i<=k;i++){
    	int x;
    	cin>>x;
    	pq.push(x);
	}
	// 然后只用再插入n-k个元素,时间复杂度为O((n-k)logk) 
    for(int i=k+1;i<=n;i++){
    	int x;
    	cin>>x;
    	if(x>pq.top()){
    		pq.pop();
    		pq.push(x); 	
		}
    	
	}

    // 再次访问顶部元素
    cout << "Top-k: " << pq.top();

    return 0;
}
  1. 方法三:
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

// 交换函数
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

// 快速选择算法
int quickSelect(int arr[], int left, int right, int k) {
    if (left == right) {
        return arr[left];
    }
    
    // 选择随机的枢纽元素
    srand(time(NULL));
    int pivotIndex = left + rand() % (right - left + 1);
    int pivot = arr[pivotIndex];
    
    // 将枢纽元素放到正确的位置上
    swap(arr[pivotIndex], arr[right]);
    int i = left;
    for (int j = left; j < right; ++j) {
        if (arr[j] > pivot) {
            swap(arr[i], arr[j]);
            ++i;
        }
    }
    swap(arr[i], arr[right]);
    
    // 根据枢纽元素的位置调整递归范围
    if (k == i) {
        return arr[i];
    } else if (k < i) {
        return quickSelect(arr, left, i - 1, k);
    } else {
        return quickSelect(arr, i + 1, right, k);
    }
}

int main() {
    int n;
    cout<<"请输入数组大小:";
    cin>>n;
    cout<<"请输入数组:";
    int arr[100]; 
    for(int i = 0; i < n; i++)
    	cin>>arr[i];
    cout<<"请输入k:";
    int k;
    cin>>k;
    int result = quickSelect(arr, 0, n - 1, k - 1); // 数组索引从0开始,所以要减去1
    cout << "top-k:" << result ;
    return 0;
}

T2

#include <iostream>

// 合并排序好的立方体
void mergeCubes(int arr[], int temp[], int left, int mid, int right) {
    int i = left, j = mid + 1, k = left;
    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    while (i <= mid) {
        temp[k++] = arr[i++];
    }
    while (j <= right) {
        temp[k++] = arr[j++];
    }
    for (int l = left; l <= right; ++l) {
        arr[l] = temp[l];
    }
}

// CubeSort 算法
void cubeSort(int arr[], int temp[], int left, int right, int cubeSize) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        cubeSort(arr, temp, left, mid, cubeSize);
        cubeSort(arr, temp, mid + 1, right, cubeSize);
        mergeCubes(arr, temp, left, mid, right);
    }
}

int main() {
    int arr[] = {3, 2, 1, 5, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    int cubeSize = 2; // 设置立方体大小为2
    int* temp = new int[n];
    cubeSort(arr, temp, 0, n - 1, cubeSize);

    std::cout << "排序后的数组: ";
    for (int i = 0; i < n; ++i) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    delete[] temp;

    return 0;
}
  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值