【问题标题】:Sorting Array of Pointers in C++在 C++ 中对指针数组进行排序
【发布时间】:2013-08-05 19:24:08
【问题描述】:

希望我能就我所做的排序方法得到一些建议。

此代码的目的是创建一个 int 指针数组,并按常规 int 数组的内容对该数组中的指针进行排序。然后根据原始 int 数组的位置为不同的变量赋值。

我在这段代码中遇到的奇怪之处是,据我所知,测试代码不应该影响任何事情......实际上正在影响我的指针的内容。 也许值没有改变,但我编写测试代码的方式导致了错误。

 //create array
 int c[8] = {3,1,5,7,8,2,6,4};
 //create pointer array
 int *newptr[8];
 for(int k = 0; k<8; k++)
 {
     newptr[k] = &c[k];
 }
//sort pointer array
for(int j = 0; j<8; j++)
{
    for(; j > -1 && *newptr[j] < *newptr[j+1]; j--)
    {
        int *temp = newptr[j+1];
        newptr[j+1] = newptr[j];
        newptr[j] = temp;
    }
}
//set lookuplocation
int lookuplocation;
for(int i = 0; i<8; i++)
{
    cout << *newptr[i];

    if(newptr[i] == &c[0])
    {
        cout << *newptr[i] << endl;

        //If I use endl or \n to test the pointers values I end up with only
        //a part of the correct data. 

        cout << "\nSuccess!\n";
        lookuplocation = 0;
    }
}
//Also for my last test sometimes the first element gets messed up as well
//test arrays
for(int k = 0; k<8; k++)
{
    cout << "Element " << k << ": " << *newptr[k] << endl;
    cout << "Element " << k << ": " << newptr[k] << endl;
}

【问题讨论】:

  • 你的排序搞砸了
  • 具有相同计数器 j 的嵌套循环?它到底是怎么工作的?
  • 是需要编写代码对指针数组进行排序,还是需要对指针数组进行排序?请指定哪个。如果你不需要自己写代码,解决方法很简单。
  • “我并没有真正在课堂上被教导使用它们(STL 容器)。” - 你当然没有,因为每个人都知道 C++ i> 最好先教 "C with cout"。 ;)
  • 您的代码有错误。在排序循环中,当j==7 表达式newptr[j+1] 访问数组末尾之后的元素时。

标签: c++ arrays algorithm sorting pointers


【解决方案1】:
void sortList(int* list, const size_t &len)
{
    for(size_t i = 0; i < len; ++i)
    {
        for (size_t j = i+1; j < len; ++j)
        {
            if (list[i] > list[j])
            {
                std::swap(list[i], list[j]);
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    我认为有人可能实际上需要以理智的方式对指针数组进行排序:

    #include <iostream>
    #include <array>
    #include <algorithm>
    
    int main() {
        std::array<int, 8> arr { 3, 5, 4, 1, 2, 7, 6, 8 };
        std::array<int*, 8> p_arr;
    
        for (unsigned i = 0; i < 8; ++i) {
            p_arr[i] = &arr[i];
        }
    
        std::sort(p_arr.begin(), p_arr.end(), [](int* a, int* b) { return *a < *b; });
    
        for (auto i : p_arr) 
            std::cout << *i;
    }
    

    丑陋的中间循环完全可以用范围替换超过zippped 范围,但我现在没有自己的引用语义实现,我懒得去检查 Boost 那个。1

    Here's a live sample on Coliru.

    另外,因为我认为我们应该一遍又一遍地重复这一点,直到新手理解它:

    • 不要重新发明分类轮(除非它是一个玩具实现)
    • 尽可能避免在 C++ 中使用指针。

    1这实际上很重要,以确保两个范围(在本例中为两个数组)具有相同的长度。不同的压缩约定要么要求范围具有相同的长度(否则会崩溃或抛出),或者如果其中一个范围太短,则填充空数据。虽然在这样一个简单的程序中看起来很明显,但在实际代码中要小心。

    【讨论】:

    • @user2651901 你应该学习标准库before指针。
    【解决方案3】:

    流行的方法是实现通用的sort 函数,该函数使用给定的比较器对元素进行排序,因此您可以对数组元素进行抽象。有几种方法:

    template<typename ElementType, typename CompType>
    void sort(ElementType array[], size_t size, CompType cmp);
    template<typename ElementType, typename CompType>
    void sort(std::vector<ElementType> & array, CompType cmp);
    template<typename IteratorType, typename CompType>
    void sort(IteratorType first, IteratorType last, CompType cmp);
    

    最后一种方式更可取,因为您也可以对容器类型进行抽象。

    【讨论】:

      【解决方案4】:

      如果您的数组c[n] 的范围为 [1 .. n],您可以使用以下算法,它的时间复杂度为 O(n):

      for(int j = 0; j < n; j++)
          while(*newptr[*newptr[j] - 1] != *newptr[j])
              std::swap(newptr[*newptr[j] - 1], newptr[j]);
      

      其背后的想法是将值 1 分配给指针 newptr[0],将值 2 分配给指针 newptr[1],...,并将 n 分配给指针 newptr[n-1]。没有比这更高效的算法了(尤其是在 C++11 中,因为 std::swap 将使用 std::move)。

      所以对于int c[8] = {3,1,5,7,8,2,6,4},你得到(忽略对值表的引用):

      1233

      成功!
      45678


      更新:如果你想要相反的顺序:

      for(int j = 0; j < n; j++)
          while(*newptr[n - *newptr[j]] != *newptr[j])
              std::swap(newptr[n - *newptr[j]], newptr[j]);
      

      对于int c[8] = {3,1,5,7,8,2,6,4},你得到:

      8765433

      成功!
      21

      【讨论】:

      • 虽然这确实有效,但它以相反的方式排序,我确信可以轻松修复。但是我正在处理的主要问题是了解我是否可以比较原始 int 数组的地址和指针。我现在很确定这就是搞砸我的代码的原因。
      • @user2651901:您的意思是您希望脚本从 8 到 1 而不是 8 到 1 排序?
      • 是的 8 比 1 不是 1 比 8。
      • 虽然这已经发布了很长时间,但我认为有必要指出这并不完全是 O(n)。
      【解决方案5】:

      先改变这个:

      for(; j &gt; -1 &amp;&amp; *newptr[j] &lt; *newptr[j+1]; j--)

      进入

      for(int i=j; i &gt; -1 &amp;&amp; *newptr[i] &lt; *newptr[i+1]; i--)

      这似乎更有效率..

      【讨论】:

      • 但非常混乱。在这一点上,简单对我来说更重要。
      • 不是,重复使用同一个 j 会让人困惑,它实际上可能会降低外循环中的 j,这可能不是目的?
      • 嗯。现在想来,它确实减少了数字的处理量。这不是必需的,但这是一个好主意。谢谢!
      • @irW “很多”效率更高? link
      • 是的,你是对的,它不会产生很大的影响,但减少外循环中的 j 仍然是愚蠢的,因为没有理由这样做。 (当我写“很多”时,我每次都假设 j -> 0 是不正确的)
      猜你喜欢
      • 1970-01-01
      • 2017-05-07
      • 2014-05-16
      • 2012-02-25
      • 1970-01-01
      • 1970-01-01
      • 2020-10-01
      相关资源
      最近更新 更多