基础排序算法【快速排序+优化版本+非递归版本】

简介: 任取待排序元素序列中的某个元素作为基准值key,按照该基准值将待排序列分成两个子序列,左子序列都比key小,右基准值都比key大。然后左右子序列重复上面的操作,直到所有元素都排列到相应的位置上为止。

基础排序算法【快速排序+优化版本+非递归版本】💯💯💯


c69669d21df244c787cce5637d52a15b.png93b6b88196fc441280b30d36273d8606.gif


⏰【快速排序】


快速排序是Hoare提出的一种二叉树结构的交换排序方法


> 基本思想:


任取待排序元素序列中的某个元素作为基准值key,按照该基准值将待排序列分成两个子序列,左子序列都比key小,右基准值都比key大。然后左右子序列重复上面的操作,直到所有元素都排列到相应的位置上为止。


而为什么说它是一种二叉树结构的交换排序方法呢?


是因为它的排序框架和二叉树的前序遍历规则十分相似。


进行一趟排序的效果是什么?


将小于key的值都放到key的左边,大于key的值都放到key的右边。


key将序列分成两个左右子序列,再对左右子序列重复上面的操作,就可以实现排序。而这一操作可以由递归实现。对左右子序列递归,直到没有子序列为止。


【快排基本框架】
void QuickSort(int *a, int left, int right)
{
  if (left>=right)
    return;
  // 按照基准值key对a数组的 [left, right)区间中的元素进行划分
  int keyi = partion(a, left, right);
  // 划分成功后以key为边界形成了左右两部分 [left, keyi-1] 和 [keyi+1, right)
  // 递归排[left, keyi-1]左子序列
  QuickSort(a, left, keyi-1);
  // 递归排[keyi+1+1, right)右子序列
  QuickSort(keyi, keyi + 1, right);
}


我们发现它与二叉树的前序遍历规则非常像,前序遍历是先访问根节点,然后再到左子树,右子树。


而这里类似,先将key排序好,然后再到左子序列,右子序列中去。所以我们在写递归框架时,可以想象二叉树前序遍历规则即可快速写出来。


◽1.hoare法


> 如何找key?


key的选值没有规定必须选哪一个,通常序列的最左边或者最右边作为key。


> 单趟排序:


单趟排序的效果也就是让key到正确的位置上去,key左边都比它小,右边都比它大。那如何做到这样呢?


  • 1.左边作key,右边先走。

  • 2.右边找比key小的值,左边找比key大的值。

  • 3.当两边都找到了就交换。

  • 4.当左边和右边相遇,将key和相遇点交换


1680ac55f1be405688cd6cee905396c8.png


a3c6c4a82b184f6abdbeddbc9dda1354.gif

void Quicksort1(int*a,int left,int right)//需要区间范围
 {       int keyi = left;
  while (left < right)
  {
    //右找小
    while (left<right && a[right]>=a[keyi])
      right--;
    //左找大
    while (left < right && a[left] <= a[keyi])
      left++;
    //交换右边的小和左边的大
    Swap(&a[left], &a[right]);
  }
  //最后将key值与left和right相遇位置交换
  Swap(&a[keyi], &a[left]);
}


> 细节1


在找小找大的过程中,要注意lleft和right的范围,虽然在外面已经控制left小于right,但找小和找大的过程不受该限制,所以还需要判断一下。


> 细节2


在找小和找大的过程中,当遇到与key大小一样的值,该怎么办,当遇到与key一样的值时,想一下,这样的值在key的左边和右边都不影响结果,所以直接跳过即可,所以在找小找大时遇到相等的也跳过去。


> 问题1:为什么左边作key右边先走

> 问题2:为什么最后相遇点比key小


单趟排序写好了接下来就是写总趟了。


其实单趟写完后,剩下的就简单多了,单趟将key放入正确的位置,并且将序列分割成两个区间,在左区间中再选取个key,放入正确位置后,又分割成两个区间,在去左子序列中分割,直到最后子序列无法分割,递归就往回返。当左区间有序后再去分割右区间,右区间选key后再分割,跟左区间操作一致。


810a9c0d18a947d29bb50ad9f8aa3a50.png

void Quicksort1(int*a,int left,int right)//需要区间范围
{
  //递归结束条件--子序列无法再分割
  if (left >= right)
    return;
  int keyi = left;
  int begin = left;//递归需要用到左右区间,需要改动区间的值,这里我们保存左右区间的值。
  int end = right;
  while (left < right)
  {
    //右找小
    while (left<right && a[right]>=a[keyi])
      right--;
    //左找大
    while (left < right && a[left] <= a[keyi])
      left++;
    //交换右边的小和左边的大
    Swap(&a[left], &a[right]);
  }
  //最后将key值与left和right相遇位置交换
  Swap(&a[keyi], &a[left]);
  keyi = left;//要将最后keyi的位置更新下
  //begin   keyi-1 key keyi+1   end
  Quicksort1(a, begin, keyi - 1);//递归左区间
  Quicksort1(a, keyi + 1, end);//递归右区间
}


◽2.挖坑法


> 单趟排序:


挖坑法,本质上也是选出一个key,最后让key的左边都小于key,key的右边都大于key。


  • 1.先将key值保存下来,那key原先的位置上就形成一个坑

  • 2.右边找小,找到后将小的放入坑内,自己位置上形成坑

  • 3.左边找大,找到后将大的放入坑内,自己位置上形成坑

  • 4.最后左右相遇,将key的值放入坑内。


挖坑法其实和霍尔的方法目的是一样的,都是将小的甩到左边,大的甩到右边。只是方法不同。


2ecd67e4889e46bf938da7607d82f3ee.png


0aac46b2e6e84525a8ee835b8397a0d2.gif


    int key = a[left];
  int hole = begin;
  while (left < right)
  {
    //右边找小
    while (left < right && a[right] >= key)
      --right;
    //找到之后将它甩到坑里,自己形成新的坑
    a[hole] = a[right];
    hole = right;
    while (left < right && a[left] <= key)
      ++left;
    //找到之后将它甩到坑里,自己形成新的坑
    a[hole] = a[left];
    hole = left;
  }
  //最后left和right相遇,将key插入到坑里
  a[hole] = key;


单趟排序完后的结果也是让key的左边都比key小,key的右边都比key大。


而接下来的总趟跟霍尔的一样,都是递归左右子序列即可。


//2.挖坑法
void Quicksort2(int* a, int left, int right)
{
  if (left >= right)
    return;
  //将key的值保留
  int key = a[left];
  int begin = left;
  int end = right;
  int hole = begin;
  //三数取中,不是取数组中间的数,而是取三个数中中间的数--begin mid end
  int midi = Midi(a, begin, end);
  Swap(&key, &a[midi]);
  while (left < right)
  {
    //右边找小
    while (left < right && a[right] >= key)
      --right;
    //找到之后将它甩到坑里,自己形成新的坑
    a[hole] = a[right];
    hole = right;
    while (left < right && a[left] <= key)
      ++left;
    //找到之后将它甩到坑里,自己形成新的坑
    a[hole] = a[left];
    hole = left;
  }
  //最后left和right相遇,将key插入到坑里
  a[hole] = key;
  Quicksort2(a, begin, hole - 1);//递归左子序列
  Quicksort2(a, hole + 1, end);//递归右子序列
}


◽3.前后指针法


第三种方法:前后指针法,顾名思义有两个指针cur和prev,该思路与霍尔和挖坑法截然不同。

它是将大的数据往右"推",将大的数据翻滚到右边去,小的数据交换到左边去。


> 单趟排序:


  • 1.刚开始prev指向起始位置(最左边作key),cur指向prev后面的位置

  • 2.cur用来找小,当cur往后找小时,找到之后,prev++,再将prev指向的元素和cur交换,cur再++。

  • 3.当cur遍历完序列后,将key直接和prev指向的数据交换即可。


176b5f7d09924a6d89cadf9cea1041e7.png

b64b260dce6d4b92a863fb3d1523f2b7.gif


void Quicksort3(int* a, int left, int right)
{
  if (left >= right)
    return;
  int keyi = left;//最左边作key
  int cur = left + 1;//cur指向prev的后面
  int prev = left;//prev指向序列起始位置
  //cur用来找小,当cur找到小时,prev++,prev的值与cur的值交换,cur继续往后走
  while (cur <= right)//当cur遍历完序列才可以结束
  {
    if (a[cur] <= a[keyi] && ++prev != cur)//如果cur找到比key小的数,那cur和prev直接的就是紧挨着,prev++后就会跟cur一样那指向的值也是一样,那就没有必要交换。当cur没到到比key小的数时,prev和cur之间就会出现距离。
    {
      Swap(&a[cur], &a[prev]);
    }
    ++cur;//不管cur找没找到比key小的数,cur都要走的
  }
  Swap(&a[prev], &a[keyi]);//最后再将prev指向的数与key交换,这个数一定是比key要小的。
   keyi = prev;//交换完后需要更新key的位置。以便递归使用。
}


当一趟结束之后,将key排在合适的位置,就将序列分成两个子序列了,那再对两个子序列做相同的操作即可,用递归分治思想。


void Quicksort3(int* a, int left, int right)
{
  if (left >= right)
    return;
  int keyi = left;
  int cur = left + 1;
  int prev = left;
  //cur用来找小,当cur找到小时,prev++,prev的值与cur的值交换,cur继续往后走
  while (cur <= right)
  {
    if (a[cur] <= a[keyi] && ++prev!= cur)
    {
      Swap(&a[cur], &a[prev]);
    }
    ++cur;
  }
  Swap(&a[prev], &a[keyi]);
   keyi = prev;//更新key的位置
  Quicksort3(a, begin, keyi - 1);//递归左子序列
  Quicksort3(a, keyi + 1,end);//递归右子序列
}


> 注意:


prev与cur之间位置上有两种关系,要么prev紧跟着cur。


要么prev和cur之间隔着一段数据,该数据就是比prev大的数据。


当prev紧挨着cur的时,prev++就跳到cur的位置上去了,那prev的值和cur的值交换就没有意义了,因为它们代表的是同一个值。也就是如果一开始cur找小找到了,那么prev和cur就是紧挨着,当一旦找到一个比key大的数时,它们之间就会出现距离,不再紧挨着了。


◽4.特性总结


1.快速排序整体比其他排序都要好,所以才敢叫快排

2.时间复杂度O(N*logN)


da2e545e672242afa9e3289269eec4ab.png


3.空间复杂度:O(logN)

4.稳定性:不稳定。


⏰【优化版本】


想一想快排的时间复杂度是多少呢?如果我们从最坏情况讨论的话,当序列完全有序和完全逆序情况下,快速排序效率最低。


c06dd55178e64f209a9b267b6860d562.png


虽然从最后的情况下来看快速排序的时间复杂度为O(N^2)但是它是可以抢救的,它可以通过某种方法来提高效率,从而从O(N ^2)变成O(N*logN)。


f6638eb814e54d789959c8694355f286.png


◽1.随机选key


13865b3b6eb04970ad0bd66c05e22a28.png

  //随机选key
  int randi = rand() % (right - left) + begin;
  Swap(&a[keyi], &a[randi]);


在单趟排序中:


void Quicksort1(int*a,int left,int right)//需要区间范围
{
  //递归结束条件
  if (left >= right)
    return;
  int keyi = left;
  int begin = left;
  int end = right;
  //随机选key
  int randi = rand() % (right - left) + begin;
  Swap(&a[keyi], &a[randi]);
  while (left < right)
  {
    //右找小
    while (left<right && a[right]>=a[keyi])
      right--;
    //左找大
    while (left < right && a[left] <= a[keyi])
      left++;
    //交换右边的小和左边的大
    Swap(&a[left], &a[right]);
  }
  //最后将key值与left和right相遇位置交换
  Swap(&a[keyi], &a[left]);
  keyi = left;


随机选key的意义,本来最左边可能是最小值或者最大值,有可能会遇到有序情况和完全逆序情况,但是随机选key大大降低了这种可能,从而提高效率。


◽2.三路取中


三路哪三路呢?


左下标,右下标,和中间下标。


取中是什么意思?


我们要取的是三个下标中所代表的值是中间值的那个数。


找到之后,就将该中间值与最左边的key交换。那么key的值就不可能为最小值或者最大值。


这样就完全确定key不是最小值了,不像随机选key还有一丢丢的可能。


所以三路取中更科学更有可用性。


怎么取出三个数中的中中间值呢?就比较即可。


int Midi(int* a, int left, int right)
{
  int mid = (left + right) / 2;//获得中间下标
  if (a[left] > a[mid])
  {
    if (a[mid] > a[right])//a[left]>a[mid]>a[great]
    {
      return mid;//mid的是中间值下标
    }
    else//a[left]>a[mid]且a[right]>a[mid] 左右两个值都大于中间的,那左右两个值再比较得中间
    {
      if (a[left] > a[right])
      {
        return right;//right是两个数中小的,也就是三个数中中间数
      }
      else
      {
        return left;//否则left就是中间数的下标
      }
    }
  }
  else//a[left]<a[mid]
  {
    if (a[mid] < a[right])
    {
      return mid;
    }
    else//a[left]<a[mid]且a[right]<a[mid]
    {
      if (a[left] > a[right])
      {
        return left;
      }
      else
      {
        return right;
      }
    }
  }
}


最后返回的都是三个数中中间值。


利用三路取中单趟排序:


void Quicksort1(int*a,int left,int right)//需要区间范围
{
  //递归结束条件
  if (left >= right)
    return;
  int keyi = left;
  //三数取中,不是取数组中间的数,而是取三个数中中间的数--begin mid end
  int midi=Midi(a, left, right);
  Swap(&a[keyi], &a[midi]);//将中间值与key交换,key就永远不可能为最小值或最大值了。
  while (left < right)
  {
    //右找小
    while (left<right && a[right]>=a[keyi])
      right--;
    //左找大
    while (left < right && a[left] <= a[keyi])
      left++;
    //交换右边的小和左边的大
    Swap(&a[left], &a[right]);
  }
  //最后将key值与left和right相遇位置交换
  Swap(&a[keyi], &a[left]);
  keyi = left;


◽3.小区间优化


我们想一颗满二叉树它最后一层节点的个数是多少?


如果这颗数的深度为h,那么最后一层的节点数就是2^(h-1)而这么多节点,这么多节点需要大量的栈帧,而且最后几层的节点数是总课数节点的一半还多。而且最后一层要递归很多次才可以到达,这样的递归的缺点就显现出来了。所以有些人就在想当递归到一定程度就不再递归,用另一种方式进行排序。


也就是当区间不断的缩小,缩小到一定范围,用直接插入排序的效果要比递归好,这样也可以做到优化效果。


因为对于数据量小的,虽然区间多,但插入排序嘎嘎快,对于快速排序这些区间需要递归很多次才可以完成所以使用这样的小区间优化来提高效率。


//3.前后指针方法
void Quicksort3(int* a, int left, int right)
{
  if (left >= right)
    return;
  //三数取中,不是取数组中间的数,而是取三个数中中间的数--begin mid end
  int midi = Midi(a, left, right);
  Swap(&a[left], &a[midi]);
  int keyi = left;
  int cur = left + 1;
  int prev = left;
  //cur用来找小,当cur找到小时,prev++,prev的值与cur的值交换,cur继续往后走
  while (cur <= right)
  {
    if (a[cur] <= a[keyi] && a[++prev] != a[cur])
    {
      Swap(&a[cur], &a[prev]);
    }
    ++cur;
  }
  Swap(&a[prev], &a[keyi]);
   keyi = prev;
   //小区间优化--当区间小时,直接使用插入排序
   if(right-left+1>10)//当区间大于10时,仍然进行递归
   {
       Quicksort3(a, left, keyi - 1);
       Quicksort3(a, keyi + 1,right);
  }
  else
  {
       InsertSort(a+left,right-left+1);//注意这里是将a+left传过去,因为不一定就是左区间,还可能是右区间
  }
}


⏰【非递归版本】


递归真正的问题是什么?


  • 1.效率不行,但现阶段效率方面都差不多

  • 2.深度太深,系统跑不过去会造成栈溢出。


因为递归是要消耗空间的,递归一次就需要建立一个栈帧,最后栈区域的内存不够了,就会造成栈溢出。


所以我们需要掌握这样的能力:将递归改成非递归。


递归改成非递归有两种思路:


  • 1.直接改成循环—如斐波那契数列

  • 2.使用(栈)辅助来改循环。


这里我们将会用栈来辅助将递归改成循环。


> 基本思路:


我们要思考排序递归函数里到底存放的是什么,每次递归什么发生了改变?对!


其实本质就是区间


每次递归函数区间都会被分割,缩小。所以我们在栈里存放的也就是区间通过栈里的区间对序列进行分割,不再使用递归分治的方法分割区间。


  • 1.首先将最初的序列左右区间入栈,要想使用左区间需要先将右区间入栈,然后左区间再入栈(栈的特点)。

  • 2.然后就开始使用栈来辅助修改循环。当栈不为空栈时,就将栈里区间出栈,一次出两个值,也就是左右区间。当左右区间出栈后,我们就可以根据左右区间对序列进行单趟排序选出key,key就将序列分成两个子序列,而这两个子序列又代表着两个区间,再将它们入栈,注意要先将右子序列区间入栈再将左序列区间入栈,然后再出栈重复上面的操作。

  • 3.当出栈的区间拿来分割子序列时,子序列无法再分割了没有区间,就不用入栈。


void QuickSortNoN(int* a, int left, int right)
{
  Stack st;
  StackInit(&st);//初始化栈
  //首先将序列的左右区间入栈
  StackPush(&st, right);
  StackPush(&st, left);
  //开始使用栈辅助修改循环
  while (!StackEmpty(&st))
  {
    //当栈不为空时,将区间出栈--出两个元素
    int begin = StackTop(&st);
    int end = StackTop(&st);
    //将区间出来后,就利用改区间对序列进行单趟排序
    int midi = Midi(a, left, right);
    Swap(&a[left], &a[midi]);
    int keyi = left;
    int cur = left + 1;
    int prev = left;
    //cur用来找小,当cur找到小时,prev++,prev的值与cur的值交换,cur继续往后走
    while (cur <= right)
    {
      if (a[cur] <= a[keyi] && a[++prev] != a[cur])
      {
        Swap(&a[cur], &a[prev]);
      }
      ++cur;
    }
    Swap(&a[prev], &a[keyi]);
    keyi = prev;
    //[left   keyi-1]  [keyi+1  right] 
   //单趟排序完后选出key ,而key又将序列分成两个子序列,相当于两个区间,将这两个区间入栈,注意先将右区间入栈,再入左区间
  //还有要注意的是,当子序列无法再分割时,无法产生区间时就不入栈
    if (left < keyi - 1)
    {
      StackPush(&st, right);
      STackPush(&st, keyi + 1);
    }
    if (keyi + 1 < right)
    {
      StackPush(&st, keyi - 1);
      StackPush(&st, left);
    }
  }
  //当栈里没有区间时序列就已经排序好了。
}


⏰【测试效率】


接下来就是测试快排的效率如何了。


我们可以拿希尔排序进行比较,也可以拿快排自己的三种方法进行比较。


void QuickTest1()
{
  srand(time(0));
  const int N = 1000000;
  int* a2 = (int*)malloc(sizeof(int) * N);
  for (int i = 0; i < N; ++i)
  {
    a2[i] = rand();
  }
  int begin1 = clock();
  Quicksort1(a2, 0, N - 1);
  int end1 = clock();
  printf("霍尔-Quicksort:%d\n", end1 - begin1);
  free(a2);
}
void QuickTest2()
{
  srand(time(0));
  const int N = 1000000;
  int* a2 = (int*)malloc(sizeof(int) * N);
  for (int i = 0; i < N; ++i)
  {
    a2[i] = rand();
  }
  int begin1 = clock();
  Quicksort2(a2, 0, N - 1);
  int end1 = clock();
  printf("挖坑法-Quicksort:%d\n", end1 - begin1);
  free(a2);
}
void QuickTest3()
{
  srand(time(0));
  const int N = 1000000;
  int* a2 = (int*)malloc(sizeof(int) * N);
  for (int i = 0; i < N; ++i)
  {
    a2[i] = rand();
  }
  int begin1 = clock();
  Quicksort3(a2, 0, N - 1);
  int end1 = clock();
  printf("前后指针-Quicksort:%d\n", end1 - begin1);
  free(a2);
}
void ShellsortTest()
{
  srand(time(0));
  const int N = 1000000;
  int* a2 = (int*)malloc(sizeof(int) * N);
  for (int i = 0; i < N; ++i)
  {
    a2[i] = rand();
  }
  int begin1 = clock();
  Shellsort(a2, N);
  int end1 = clock();
  printf("希尔Shellsort:%d\n", end1 - begin1);
  free(a2);
}
int main()
{
  QuickTest1();
  QuickTest2();
  QuickTest3();
  ShellsortTest();
  return 0;
}

72f84dc81ecf406386a8dd84e417622b.png


排序OJ(可使用各种排序跑这个OJ)

相关文章
|
5天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
2天前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
17 4
|
5天前
|
人工智能 算法 大数据
Linux内核中的调度算法演变:从O(1)到CFS的优化之旅###
本文深入探讨了Linux操作系统内核中进程调度算法的发展历程,聚焦于O(1)调度器向完全公平调度器(CFS)的转变。不同于传统摘要对研究背景、方法、结果和结论的概述,本文创新性地采用“技术演进时间线”的形式,简明扼要地勾勒出这一转变背后的关键技术里程碑,旨在为读者提供一个清晰的历史脉络,引领其深入了解Linux调度机制的革新之路。 ###
|
15天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。
|
15天前
|
存储 缓存 算法
优化轮询算法以提高资源分配的效率
【10月更文挑战第13天】通过以上这些优化措施,可以在一定程度上提高轮询算法的资源分配效率,使其更好地适应不同的应用场景和需求。但需要注意的是,优化策略的选择和实施需要根据具体情况进行详细的分析和评估,以确保优化效果的最大化。
|
18天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
3天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
5天前
|
存储 算法 决策智能
基于免疫算法的TSP问题求解matlab仿真
旅行商问题(TSP)是一个经典的组合优化问题,目标是寻找经过每个城市恰好一次并返回起点的最短回路。本文介绍了一种基于免疫算法(IA)的解决方案,该算法模拟生物免疫系统的运作机制,通过克隆选择、变异和免疫记忆等步骤,有效解决了TSP问题。程序使用MATLAB 2022a版本运行,展示了良好的优化效果。
|
5天前
|
机器学习/深度学习 算法 芯片
基于GSP工具箱的NILM算法matlab仿真
基于GSP工具箱的NILM算法Matlab仿真,利用图信号处理技术解析家庭或建筑内各电器的独立功耗。GSPBox通过图的节点、边和权重矩阵表示电气系统,实现对未知数据的有效分类。系统使用MATLAB2022a版本,通过滤波或分解技术从全局能耗信号中提取子设备的功耗信息。
|
5天前
|
机器学习/深度学习 算法 5G
基于MIMO系统的SDR-AltMin混合预编码算法matlab性能仿真
基于MIMO系统的SDR-AltMin混合预编码算法通过结合半定松弛和交替最小化技术,优化大规模MIMO系统的预编码矩阵,提高信号质量。Matlab 2022a仿真结果显示,该算法能有效提升系统性能并降低计算复杂度。核心程序包括预编码和接收矩阵的设计,以及不同信噪比下的性能评估。
21 3
下一篇
无影云桌面