固定长度结构重新排列:我应该使用数组还是链表

Fixed length structure re-arrange: should I use array or linked list?

本文关键字:我应该 数组 链表 排列 结构 新排列      更新时间:2023-10-16

此结构只包含256个无符号字符。唯一可能的操作是从中提取随机字符,并将它们放在结构前面。例如:

A= 'abcdef'

将字符2移到前面

A= 'cabdef'

我首先想到的是使用链接链接,这样它就可以作为队列工作。问题是,我听说数组在这些操作中比链表快得多。这是真的吗?

如您所述,对于移动操作,链表将为O(1),数组将为O。对于小型n,阵列可能会更快,但唯一确定的方法是进行基准测试。

在这样的情况下,我会编写最清晰的代码,只有当它被证明是一个瓶颈时,我才会担心效率。

附言:我假设你已经有了一个指向你想要移动的角色的指针。如果不是这样,那么在链表中查找该字符将是O(n),您将失去它可能具有的任何优势。

使用数组。对于字符数据的存储来说,链表将是巨大而笨拙的。

链表是一种很好的方法,因为您不需要移动所有的中间元素。std::listsplice()结合使用效果良好。您需要一个迭代器来遍历要移到前面的元素:

#include <list>
#include <iostream>
#include "prettyprint.hpp"
int main()
{
  std::list<int> x { 1, 4, 6, 7, 2 };
  auto i = x.begin(); std::advance(i, 2);  // i points to 6
  std::cout << x << std::endl;  //  [1, 4, 6, 7, 2]
  x.splice(x.begin(), x, i);
  std::cout << x << std::endl;  //  [6, 1, 4, 7, 2]
}

(使用漂亮的打印机进行快速演示。)

正如其他人所说,这是否比随机访问容器更有效取决于您如何跟踪要移动的元素。


更新:根据Steve的评论,我也想提供一个原始的C阵列解决方案。它的优点是,您可以在O(1)时间内通过位置访问它,并且它需要最小的空间:

char y[] = { 'a', 'c', 'Q', '%', '5' };
std::cout << pretty_print_array(y) << std::endl; // [a, c, Q, %, 5]
std::rotate(y, y + 2, y + sizeof(y));
std::cout << pretty_print_array(y) << std::endl; // [Q, %, 5, a, c]

rotate调用可以封装在一个函数中:

template <typename T, size_t N>
void bring_forward(T (& a)[N], size_t p) { std::rotate(a, a + p, a + N); }

在C++中,可以使用vector而不是数组或链表。链表的复杂性是O(1),就像@Mark Ransom说的那样。使用矢量,可以使用命令rotate来执行所需的操作。复杂性由掉期的数量决定。

从MSDN,如何使用rotate:

   const int VECTOR_SIZE = 8;
   // Define a template class vector of strings
   typedef vector<string> StrVector;
   //Define an iterator for template class vector of strings
   typedef StrVector::iterator StrVectorIt;
   StrVector Tongue_Twister(VECTOR_SIZE);
   StrVectorIt start, end, middle, it;
   // location of first element of Tongue_Twister
   start = Tongue_Twister.begin();   
   // one past the location last element of Tongue_Twister
   end = Tongue_Twister.end();       

   // Initialize vector Tongue_Twister
   Tongue_Twister[0] = "she";
   Tongue_Twister[1] = "sells";
   Tongue_Twister[2] = "sea";
   Tongue_Twister[3] = "shells";
   Tongue_Twister[4] = "by";
   Tongue_Twister[5] = "the";
   Tongue_Twister[6] = "sea";
   Tongue_Twister[7] = "shore";
   middle = start + 3;  // start position for rotating elements
   cout << "Before calling rotate" << endl;
   // print content of Tongue_Twister
   cout << "Try this Tongue Twister:";
   for (it = start; it != end; it++)
      cout << " " << *it;
   // rotate the items in the vector Tongue_Twister by 3 positions
   rotate(start, middle, end);

或者你可以用阵列来做:

// create an array of 9 elements and rotate the entire array.
int myArray[SIZE] = { 7, 8, 9, 1, 2, 3, 4, 5, 6,  };
std::rotate(myArray, myArray + 3, myArray + SIZE);

这有多快?我不知道。我还没有对它进行基准测试。但它比手动交换数组元素要容易得多。

数组将为O(1)以查找项,为O(n)以将它和其他项移动到正确的位置。链表将为O(n)以查找项目,为O(1)以将所有内容移动到正确的位置。无论哪种方式,复杂性都是一样的。

它们都很容易实现,所以实现它们并运行测试,看看哪一个可以让你的程序在真实世界的数据中更快地运行。

C++数组是链表,因此如果您已经知道元素在哪里(即,上面有迭代器),那么将元素移动到列表的前面是很便宜的。使用向量会导致每次将元素推到整个列表前面时都会移动整个列表。