归并排序功能(自然归并排序)

发布于 2024-11-19 17:58:49 字数 4623 浏览 4 评论 0原文

有几种方法可以进行合并排序,但我特别需要它像自然合并排序一样工作。该算法会在文件中生成较小的数字列表,如下所示:

原始列表: 35 27 24 28 31 37 1 4 7 6 8 9

较小的列表部分: [35], [27], [24, 28 ], [31, 37], [1, 4, 7], [6, 8, 9]

正如你所注意到的,每次遇到未排序的列表如果数字小于当前值,则会创建一个新单位。一旦列表结束,该列表就会以另一种方式分成两个其他列表:

第一个列表: [35], [24, 28], [1, 4, 7]

第二个列表: [27], [31, 37 ], [6, 8, 9]

最后一步涉及将两个列表再次拉到一起,并在遍历时比较第一个列表项和第二个列表项中的单位之间的值。例如,列表一中的第一个单元与列表二中的第一个单元进行比较,并保持数字的顺序。任何剩余的单位将添加到末尾(未显示)。

合并两个列表:[27, 35], [24, 28, 31, 37], [1, 4, 6, 7, 8, 9]

重复此过程,直到列表按一个单元排序。

除了合并两个列表之外,我已经在该算法中设置了所有内容,并且可以正常工作,并且调试或定位问题非常困难。在进入分段错误之前,它大约进行了一半。不管怎样,我不能在这个程序上使用归并排序STL,它都在一个链接列表中。

注意:构造函数和其他必要的函数已经就位。我故意省略了其他功能以体现特定功能。

class mergeList
{
   public:

      //Setters
      void setNumber(int item);
      void setStart(bool newStatus);
      void setEnd(bool newStatus);
      void setPrev(mergeList* node);
      void setNext(mergeList* node);

      //Getters
      int getNumber();
      bool getStart();
      bool getEnd();
      mergeList* getPrev();
      mergeList* getNext();

   private:
      int number;

      bool startSection;
      bool endSection;

      mergeList* prev;
      mergeList* next;
};

class mergeListObject
{
   public:
     mergeList* firstNode;
     mergeList* lastNode;

   void mergeLists(mergeListObject &firstList,
                   mergeListObject &secondList);

   //Other functions in program are in here.
};

void mergeListObject::mergeLists(mergeListObject &firstList,
                                 mergeListObject &secondList)
{
   mergeList* combTraverse = firstNode;
   mergeList* firstTraverse = firstList.firstNode;
   mergeList* secondTraverse = secondList.firstNode;

   bool listDone = false;

   //This will clear the combination list for insertion
   while (combTraverse != NULL)
   {
      combTraverse->setNumber(-1);
      combTraverse->setStart(false);
      combTraverse->setEnd(false);

      combTraverse = combTraverse->getNext();
   }

   combTraverse = firstNode;

   combTraverse->setStart(true);

   while (listDone == false)
   {
      //This will go until the first list is traversed.
      do
      {
         bool exception = false;

         int j = firstTraverse->getNumber();
         int k;

         //If the second list is still active, this will
         //grab its current value for comparison.
         if (secondTraverse != NULL)
            k = secondTraverse->getNumber();

         //Second list is done, will automatically grab
         //first list's value and traverse through to the end.
         if (secondTraverse == NULL)
            combTraverse->setNumber(firstTraverse->getNumber());

         else
         {
            //Both values from both lists are compared.
            if (j <= k)
               combTraverse->setNumber(firstTraverse->getNumber());

            else
            {
                exception = true;
                combTraverse->setNumber(secondTraverse->getNumber());
            }
         }

         //If the first value unit was used, move the first list iterator up.
         //Otherwise, the second list's iterator moves up.
         if (exception == false)
            firstTraverse = firstTraverse->getNext();

         else
            secondTraverse = secondTraverse->getNext();

         exception = false;
      }
      while (firstTraverse->getEnd() == false);

      //If the second list isn't done, this will finish it.
      do
      {
         combTraverse->setNumber(secondTraverse->getNumber());

         secondTraverse = secondTraverse->getNext();
         combTraverse = combTraverse->getNext();
      }
      while (secondTraverse->getEnd() == false);

      combTraverse->setEnd(true);

      //Marks the end of the section and sets the next one,
      //considering it isn't the end of the list.
      if (combTraverse->getNext() != NULL)
         combTraverse->getNext()->setStart(true);

      //Both of these should end up at the start of a unit in their own lists.
      firstTraverse = firstTraverse->getNext();
      secondTraverse = secondTraverse->getNext();

      //Are both lists done?
      if (firstTraverse == NULL &&
          secondTraverse == NULL)
         listDone = true;
   }

   return;
}

int main()
{
   mergeListObject one;
   mergeListObject two;
   mergeListObject combined;

   //The two lists are already separated. All
   //other functions have already been called.

   combined.mergeLists(one, two);

   return 0;
} 

There are a few ways to do a merge sort, but I specifically need it to work like a natural merge sort. What happens in this algorithm is that smaller lists of numbers are generated in the file like so:

Original List: 35 27 24 28 31 37 1 4 7 6 8 9

Smaller List sections: [35], [27], [24, 28], [31, 37], [1, 4, 7], [6, 8, 9]

As you notice, everytime the unsorted list comes across a number that's smaller than it's present value, a new unit is created. Once the list ends, this list breaks into two other lists like so in an alternative fashion:

First list: [35], [24, 28], [1, 4, 7]

Second list: [27], [31, 37], [6, 8, 9]

The last step involves pulling the two lists together again, and the values are compared between the units in the first list item and the second list item as it traverses. For example, first unit in list one is compared with the first unit in list two and keeps the numbers in order. Any leftover units will be added on the end(Not shown).

Merging two lists: [27, 35], [24, 28, 31, 37], [1, 4, 6, 7, 8, 9]

This process will repeat until the list is sorted in one unit.

I have everything set up in this algorithm to work except for merging the two lists and it's extremely hard to debug or locate the problem. It gets about halfway through before it goes into a segmentation fault. Anyways, I can't use the mergesort STL on this program and it's all in a linked list.

Note: The constructors and other necessary functions are already in place. I left out the other functions on purpose to empathize the specific function.

class mergeList
{
   public:

      //Setters
      void setNumber(int item);
      void setStart(bool newStatus);
      void setEnd(bool newStatus);
      void setPrev(mergeList* node);
      void setNext(mergeList* node);

      //Getters
      int getNumber();
      bool getStart();
      bool getEnd();
      mergeList* getPrev();
      mergeList* getNext();

   private:
      int number;

      bool startSection;
      bool endSection;

      mergeList* prev;
      mergeList* next;
};

class mergeListObject
{
   public:
     mergeList* firstNode;
     mergeList* lastNode;

   void mergeLists(mergeListObject &firstList,
                   mergeListObject &secondList);

   //Other functions in program are in here.
};

void mergeListObject::mergeLists(mergeListObject &firstList,
                                 mergeListObject &secondList)
{
   mergeList* combTraverse = firstNode;
   mergeList* firstTraverse = firstList.firstNode;
   mergeList* secondTraverse = secondList.firstNode;

   bool listDone = false;

   //This will clear the combination list for insertion
   while (combTraverse != NULL)
   {
      combTraverse->setNumber(-1);
      combTraverse->setStart(false);
      combTraverse->setEnd(false);

      combTraverse = combTraverse->getNext();
   }

   combTraverse = firstNode;

   combTraverse->setStart(true);

   while (listDone == false)
   {
      //This will go until the first list is traversed.
      do
      {
         bool exception = false;

         int j = firstTraverse->getNumber();
         int k;

         //If the second list is still active, this will
         //grab its current value for comparison.
         if (secondTraverse != NULL)
            k = secondTraverse->getNumber();

         //Second list is done, will automatically grab
         //first list's value and traverse through to the end.
         if (secondTraverse == NULL)
            combTraverse->setNumber(firstTraverse->getNumber());

         else
         {
            //Both values from both lists are compared.
            if (j <= k)
               combTraverse->setNumber(firstTraverse->getNumber());

            else
            {
                exception = true;
                combTraverse->setNumber(secondTraverse->getNumber());
            }
         }

         //If the first value unit was used, move the first list iterator up.
         //Otherwise, the second list's iterator moves up.
         if (exception == false)
            firstTraverse = firstTraverse->getNext();

         else
            secondTraverse = secondTraverse->getNext();

         exception = false;
      }
      while (firstTraverse->getEnd() == false);

      //If the second list isn't done, this will finish it.
      do
      {
         combTraverse->setNumber(secondTraverse->getNumber());

         secondTraverse = secondTraverse->getNext();
         combTraverse = combTraverse->getNext();
      }
      while (secondTraverse->getEnd() == false);

      combTraverse->setEnd(true);

      //Marks the end of the section and sets the next one,
      //considering it isn't the end of the list.
      if (combTraverse->getNext() != NULL)
         combTraverse->getNext()->setStart(true);

      //Both of these should end up at the start of a unit in their own lists.
      firstTraverse = firstTraverse->getNext();
      secondTraverse = secondTraverse->getNext();

      //Are both lists done?
      if (firstTraverse == NULL &&
          secondTraverse == NULL)
         listDone = true;
   }

   return;
}

int main()
{
   mergeListObject one;
   mergeListObject two;
   mergeListObject combined;

   //The two lists are already separated. All
   //other functions have already been called.

   combined.mergeLists(one, two);

   return 0;
} 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

演多会厌 2024-11-26 17:58:50

我发现的第一个错误是在合并函数的末尾:

firstTraverse = firstTraverse->getNext();
secondTraverse = secondTraverse->getNext();

可能会生成运行时错误(“访问冲突”或“分段错误”,具体取决于编译器和操作系统),您必须更改它以

if (firstTraverse)
    firstTraverse = firstTraverse->getNext();
if (secondTraverse)
    secondTraverse = secondTraverse->getNext();

注意这些指针实际上可以为 NULL。

您还必须将 while (firstTraverse->getEnd() == false); 更改为 while(firstTraverse & firstTraverse->getEnd() == false); 同样,只要第一个列表的分区数量少于第二个列表,firstTravers 就可以为 NULL。

The first bug I could spot was at the end of your merge function :

firstTraverse = firstTraverse->getNext();
secondTraverse = secondTraverse->getNext();

may generate runtime error ("access violation" or "segmentation fault" depending on compiler and OS) you have to change it to

if (firstTraverse)
    firstTraverse = firstTraverse->getNext();
if (secondTraverse)
    secondTraverse = secondTraverse->getNext();

note that those pointers can really be NULL.

you also have to change while (firstTraverse->getEnd() == false); to while(firstTraverse & firstTraverse->getEnd() == false); again firstTravers can be NULL as long as first list has lower number of partitions than second list.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文