算法设计与分析 实验一 排序算法性能分析(下)

简介: 算法设计与分析 实验一 排序算法性能分析(下)

(三)实验算法源码分析


详细的完整代码在附件中。

现对代码结构及实现过程进行如下解释:

1、L1~L9:

进行头文件声明


86dac256857e4fd6b4c9093e76a9484a.png


2、L11~L242:

定义各个排序函数,每个函数的实现过程中均包含详细的注释。


3c767dae87e34ceb82a120bbbea9c1df.png


3、L261~L558:

主函数:

①使用输出流创建文件,将每次程序运行的结果存入details.txt和result.txt中


4d017bda7bea4efa99bffb82ad8600fc.png


②对于每个算法,利用循环将数据量级从101~106进行测试,每次测试时,均生成20组数据,计算时间后将结果再存会result.txt和details.txt文件中。


四、实验结论或体会


①同样问题下不同的数量级有不同的处理方法并应选择不同的算法。

例如对101103 这种小数据的排序可以选择基数排序与合并排序外的六种排序方式。而对数据量大于104

的数据应该选择快速排序,合并排序,基数排序,希尔排序或堆排序。对于数据量巨大例如1012

的数据则应该选择计数排序,并应该考虑内存外存的数据搬运问题。


②既定算法是对某种普遍情况的处理方式,可能存在极端情况。

例如快速排序,当数据大小大致成二分分布时,有很好的性能,但当数据恰好倒序或恰好正序时,则性能很差。因此对于特殊情况需要选择特定算法进行处理。

③不能忽略对现有算法的优化

例如冒泡排序和选择排序,在算法进行中,存在冗余操作,即存在可优化的空间。对算法进行优化可以在算法本质不变的情况下一定程度上提高算法的效率。

④实践是检验算法的唯一标准,应避免“想当然”

例如两种“可行”的冒泡排序优化算法,从理论上都似乎可行,但实际运行起来,一种算法并不能提高运行效率反而降低了效率。这给我的启示是对于算法的学习中,一定要使用数据对算法进行实践,避免理论上的想当然。


五、思考


在本次实验过程中,我也发现了一些问题如下:


1. 冒泡排序算法优化

 传统冒泡排序算法中,排序完成的结束标准为所有循环全部循环结束。在实际算法运行中,会发现,在某次排序之后,部分序列变为有序,此时这部分序列不需进行冒泡排序。基于此,提出如下两个优化算法:

①减少无效循环次数

 不难发现在实际运行中,冒泡排序算法截止的标志是全部循环运行结束,因此可能存在在循环结束前,序列已经有序,但仍需进行循环,此时将造成时间浪费。可以通过定义标志变量判断冒泡的一趟是否进行交换,如果未进行交换则序列已经有序,break出循环减少无效循环。基于这个想法,编写代码并测试:

aefbfdc2c3174c50a8ea2d9bfee1a145.png

 从上表中可以发现,“优化”过的算法时间不仅没有减少,反而增加了。可能是因为算法几乎要全部循环结束才能完成排序,设置标志变量减少的循环次数不多。而且对标志变量赋值判断消耗的时间大于设置标志变量减少的循环消耗时间。因此不能提高算法效率!


②提高有效循环效率

 假如有一个长度为50的数组,在一趟交换后,最后发生交换的位置是10,那么这个位置之后的40个数必定已经有序了,记录下这位置,下一趟交换只要从数组头部到这个位置就可以了

基于这个想法,编写代码并测试

0692af8dc7444be79ad3d1aabe976dc6.png

可以看出,冒泡排序的时间消耗略微缩短了,算法得到了优化。

2.选择排序算法优化

  在正常的选择排序中,每次都需要对所有元素进行比较但仅获得最大/最小值,不妨在选择排序过程中,每次获得最大值和最小值,从而将选择次数缩短一半。

  基于此想法,编写代码并测试

cae788e07ad446a7ac4dddd620c6d55a.png

可以看出,选择排序的时间消耗明显缩短,大致节省了20%的时间,算法得到了优化。


3.(思考题)现在有1万亿的数据,请选择合适的排序算法与数据结构,在有限的时间内完成进行排序。


一万亿数据进行排序即对1012个整数进行排序。一个长整形占4个字节。则1012

个整数占4 × 1012≈4TB。如此巨大的数据量不可能一次放到内存中。因此需要将数据存放在外存中,并在内存外存中搬运数据完成数据的排序处理。

此时,一般的排序方法将由于无法使用,经过查阅资料后,我选择了一种非比较算法进行排序——计数排序。

(1)计数排序介绍与原理

计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为O ( n + k ) Ο(n+k)O(n+k)(其中k是整数的范围),快于任何比较排序算法。

算法具体实现如下:

①开辟一新数组,用来作为桶存每个元素出现的频率

②遍历待排序序列,将每个元素放入对应的桶中(频率值加一)

③遍历频率数组,并将每个元素存回原序列。

下面以排序2,3,8,4,6,1,3,9,4,7这10个数为例

20210601222644356.png

(2)计数排序伪代码

COUNTSORT(A):
    memset(C,sizeof(C),0);       //C数组置零    
for i=1 to n do    
    C[A[i]]++;               //统计输入数组中相同元素的个数    
for i=2 to k do    
    C[i] = C[i]+C[i-1];       //C[i]表示输入数组中小于或者等于i的元素个数    
for i=n downto 1 do    
    B[C[A[i]]] = A[i];       //把每一个A[i]放到输出数组中相应位置上    
    C[A[i]]--;             //如果有几个相同元素时,当然不能放在同一个位置了。

(3)计数排序在相对小数量级下的测试(单位ms)

通过随机数生成器生成不同测试数据,分别使用计数排序和通过实验得出对于大数据最高效的基数排序进行排序并比较时间。

d386371f29ae4fc6862c11b46fbbd8c3.png

可以看出,计数排序的时间消耗比目前最快的算法仍要快出很多。


(4)具体排序1012数据的步骤

①利用文件流创建若干个空文件,用来作为桶存各个数字出现频率。

②利用文件流,从外存中读入数字。并放入桶文件的对应位置。

③清空原数据源文件,并遍历桶文件将对应数字存入数据源文件中。


(5)时间消耗预计

由于计数排序的时间复杂度为O ( n + k ) (其中k是整数的范围)。则当排序1012个数字时,大约需要17 h


六、样例代码


//Code by:DongYunhao  2019284073
#include <algorithm>
#include <cmath>
#include <ctime>
#include <fstream>
#include <iostream>
#include <random>
#include <windows.h>
using namespace std;
堆排序
void minHeapDown(int a[], int start, int end) {
    int current = start;        // 当前(current)节点的位置
    int left = 2 * current + 1; // 为左(left)孩子的位置
    int tmp = a[current];       // 当前(current)节点的值
    for (; left <= end; current = left, left = 2 * left + 1) {
        // "left"是左孩子,"left+1"是右孩子
        if (left < end && a[left] > a[left + 1])
            left++; // 左右两孩子中选择较小者
        if (tmp <= a[left])
            break; // 调整结束
        else       // 交换值
        {
            a[current] = a[left];
            a[left] = tmp;
        }
    }
}
//堆排序(降序):交换数据,将a[1]和a[n]交换,使a[n]是a[1...n]中的最小值;然后将a[1...n-1]重新调整为最小堆。
void Heap_Sort_Desc(int a[], int n) {
    int i, tmp;
    for (i = n / 2 - 1; i >= 0; i--) // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最小)二叉堆。
        minHeapDown(a, i, n - 1);
    //交换数据
    for (i = n - 1; i > 0; i--) {
        // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最小的。
        tmp = a[0];
        a[0] = a[i];
        a[i] = tmp;
        // 调整a[0...i-1],使得a[0...i-1]仍然是一个最小堆。
        minHeapDown(a, 0, i - 1);
    }
}
希尔排序
void Shell_Sort(int a[], int n) {
    int i, j, gap;
    // gap为步长,每次减为原来的一半。
    for (gap = n / 2; gap > 0; gap /= 2) {
        // 共gap个组,对每一组都执行直接插入排序
        for (i = 0; i < gap; i++) {
            for (j = i + gap; j < n; j += gap) {
                // 如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移。
                if (a[j] < a[j - gap]) {
                    int tmp = a[j];
                    int k = j - gap;
                    while (k >= 0 && a[k] > tmp) {
                        a[k + gap] = a[k];
                        k -= gap;
                    }
                    a[k + gap] = tmp;
                }
            }
        }
    }
}
基数排序
int maxbit(int a[], int n) {
    int d = 1; //保存最大的位数
    int p = 10;
    for (int i = 0; i < n; i++) {
        while (a[i] >= p) {
            p *= 10;
            d++;
        }
    }
    return d;
}
void Radix_Sort(int a[], int n) {
    int d = maxbit(a, n);
    int *tmp = new int[n]; //int tmp[n]错误定义,数组长度必须是整数常量或整数符号常量,想要用变量设置大小,必须用动态分配
    int count[10];         //计数器
    int i, j, k;
    int radix = 1;
    for (i = 1; i <= d; i++) //进行d次排序
    {
        for (j = 0; j < 10; j++)
            count[j] = 0; //每次分配前清空计数器
        for (j = 0; j < n; j++) {
            k = (a[j] / radix) % 10; //统计每个桶中的记录数
            count[k]++;
        }
        for (j = 1; j < 10; j++)
            count[j] = count[j - 1] + count[j]; //这时count里的值表示在tmp中的位置(减一为tmp里的存储下标)
        for (j = n - 1; j >= 0; j--)            //将所有桶中记录依次收集到tmp中
        {
            k = (a[j] / radix) % 10;
            tmp[count[k] - 1] = a[j];
            count[k]--; //用于一个桶中有多个数,减一为桶中前一个数在tmp里的位置
        }
        for (j = 0; j < n; j++) //将临时数组的内容复制到data中
            a[j] = tmp[j];
        radix = radix * 10;
    }
    delete[] tmp;
}
快速排序
int quickSortPartition(int s[], int l, int r) {
    //Swap(s[l], s[(l + r) / 2]); //若以中间数为基准,则先将中间的这个数和第一个数交换即可
    int i = l, j = r, x = s[l]; //将最左元素记录到x中
    while (i < j) {
        // 从右向左找第一个<x的数
        // 无需考虑下标越界
        while (i < j && s[j] >= x)
            j--;
        if (i < j)
            s[i++] = s[j]; //直接替换掉最左元素(已在x中存有备份)
        // 从左向右找第一个>x的数
        while (i < j && s[i] <= x)
            i++;
        if (i < j)
            //替换掉最右元素(已在最左元素中有备份)
            //最左元素一定被覆盖过,若没有,则表明右侧所有元素都>x,那么算法将终止
            s[j--] = s[i];
    }
    s[i] = x; //i的位置放了x,所以其左侧都小于x,右侧y都大于x
    return i;
}
void quickSort(int s[], int l, int r) {
    //数组左界<右界才有意义,否则说明都已排好,直接返回即可
    if (l >= r) {
        return;
    }
    // 划分,返回基准点位置
    int i = quickSortPartition(s, l, r);
    // 递归处理左右两部分,i处为分界点,不用管i了
    quickSort(s, l, i - 1);
    quickSort(s, i + 1, r);
}
归并排序
void Merge(int arr[], int l, int q, int r) {
    int n = r - l + 1; //临时数组存合并后的有序序列
    int *tmp = new int[n];
    int i = 0;
    int left = l;
    int right = q + 1;
    while (left <= q && right <= r)
        tmp[i++] = arr[left] <= arr[right] ? arr[left++] : arr[right++];
    while (left <= q)
        tmp[i++] = arr[left++];
    while (right <= r)
        tmp[i++] = arr[right++];
    for (int j = 0; j < n; ++j)
        arr[l + j] = tmp[j];
    delete[] tmp; //删掉堆区的内存
}
void MergeSort(int arr[], int l, int r) {
    if (l == r)
        return; //递归基是让数组中的每个数单独成为长度为1的区间
    int q = (l + r) / 2;
    MergeSort(arr, l, q);
    MergeSort(arr, q + 1, r);
    Merge(arr, l, q, r);
}
选择排序
void Selectsort(int num[], int length) {
    int index;
    for (int i = 0; i < length - 1; i++) {
        index = i;
        for (int j = i + 1; j < length; j++) {
            if (num[index] < num[j]) {
                index = j;
            }
        }
        swap(num[index], num[i]);
    }
}
//冒泡排序
void BubbleSort(int num[], int length) {
    for (int jj = 0; jj < length - 1; jj++) {
        for (int ii = 0; ii < length - 1 - jj; ii++)
            if (num[ii] > num[ii + 1]) {
                swap(num[ii], num[ii + 1]);
            }
    }
}
插入排序
void InsertSort(int num[], int length) {
    for (int ii = 1; ii < length; ii++) {
        int jj = ii;
        int temp = num[ii];
        for (; jj > 0 && temp < num[jj - 1]; jj--) {
            num[jj] = num[jj - 1];
        }
        num[jj] = temp;
    }
}
/*主函数
*/
int main() {
    //cout << "Please input the level of quantity: " << endl;
    int level; //输入数量级
    ofstream details("details.txt");
    ofstream logs("logs.txt");
    for (level = 1; level <= 6; level++) {
        //cin >> level;
        //cout << "Please input the number of tests: " << endl;
        int numOfData;
        numOfData = 20;
        long long int length = pow(10, level);
        details << "===============================" << endl;
        logs << "===============================" << endl;
        details << "Level:" << level << " Quantity:" << length << " TestNumber:" << numOfData << endl;
        logs << "Level:" << level << " Quantity:" << length << " TestNumber:" << numOfData << endl;
        cout << "Running on " << level << endl;
        int *num = new int[length];
        /*
        选择排序
        */
        double total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            Selectsort(num, length);
            QueryPerformanceCounter(&nEndTime);
            details << "Select_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Select_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Select_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        冒泡排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            BubbleSort(num, length);
            QueryPerformanceCounter(&nEndTime);
            details << "Bubble_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Bubble_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Bubble_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        插入排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            InsertSort(num, length);
            QueryPerformanceCounter(&nEndTime);
            details << "Insert_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Insert_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Insert_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        快速排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            quickSort(num, 0, length - 1);
            QueryPerformanceCounter(&nEndTime);
            details << "Quick_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Quick_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Quick_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        归并排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            MergeSort(num, 0, length - 1);
            QueryPerformanceCounter(&nEndTime);
            details << "Merge_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Merge_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Merge_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        基数排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            Radix_Sort(num, length);
            QueryPerformanceCounter(&nEndTime);
            details << "Radix_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Radix_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Radix_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        希尔排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            Shell_Sort(num, length);
            QueryPerformanceCounter(&nEndTime);
            details << "Shell_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        logs << "Shell_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        details << "Shell_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        /*
        堆排序
        */
        total_time = 0;
        for (int t = 0; t < numOfData; t++) {
            time_t seed = time(nullptr);
            default_random_engine eng(seed);
            uniform_int_distribution<int> dist(1, length);
            for (int i = 0; i < length; i++) {
                num[i] = dist(eng);
            }
            LARGE_INTEGER nFreq;
            LARGE_INTEGER nBeginTime;
            LARGE_INTEGER nEndTime;
            QueryPerformanceFrequency(&nFreq);
            QueryPerformanceCounter(&nBeginTime);
            //排序源代码
            Heap_Sort_Desc(num, length);
            QueryPerformanceCounter(&nEndTime);
            details << "Heap_sort Test Data " << t + 1 << " time cost:"
                    << (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart * 1000 << "ms"
                    << endl;
            total_time += (double) (nEndTime.QuadPart - nBeginTime.QuadPart) / (double) nFreq.QuadPart;
        }
        details << "Heap_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
        logs << "Heap_sort Average Time Cost:" << total_time * 1000 / numOfData << "ms" << endl;
    }
    details.close();
    logs.close();
    return 0;
}
相关文章
|
1月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
58 4
|
1月前
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
26 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
|
24天前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
1月前
|
搜索推荐 算法
数据结构与算法学习十四:常用排序算法总结和对比
关于常用排序算法的总结和对比,包括稳定性、内排序、外排序、时间复杂度和空间复杂度等术语的解释。
20 0
数据结构与算法学习十四:常用排序算法总结和对比
|
30天前
|
算法
PID算法原理分析
【10月更文挑战第12天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
|
2月前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
57 4
|
1月前
|
算法
PID算法原理分析及优化
【10月更文挑战第6天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
|
2月前
|
算法 程序员 Python
程序员必看!Python复杂度分析全攻略,让你的算法设计既快又省内存!
在编程领域,Python以简洁的语法和强大的库支持成为众多程序员的首选语言。然而,性能优化仍是挑战。本文将带你深入了解Python算法的复杂度分析,从时间与空间复杂度入手,分享四大最佳实践:选择合适算法、优化实现、利用Python特性减少空间消耗及定期评估调整,助你写出高效且节省内存的代码,轻松应对各种编程挑战。
41 1
|
1月前
|
机器学习/深度学习 搜索推荐 算法
探索数据结构:初入算法之经典排序算法
探索数据结构:初入算法之经典排序算法
|
2月前
|
算法 数据可视化
基于SSA奇异谱分析算法的时间序列趋势线提取matlab仿真
奇异谱分析(SSA)是一种基于奇异值分解(SVD)和轨迹矩阵的非线性、非参数时间序列分析方法,适用于提取趋势、周期性和噪声成分。本项目使用MATLAB 2022a版本实现从强干扰序列中提取趋势线,并通过可视化展示了原时间序列与提取的趋势分量。代码实现了滑动窗口下的奇异值分解和分组重构,适用于非线性和非平稳时间序列分析。此方法在气候变化、金融市场和生物医学信号处理等领域有广泛应用。
122 19