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

时间:2011-07-12 22:14:03

标签: c++ mergesort

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

原始列表: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]

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

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

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

除了合并两个列表之外,我已经在此算法中设置了所有内容,并且调试或找到问题非常困难。它在进入分段故障之前大约一半。无论如何,我不能在这个程序上使用mergesort 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;
} 

1 个答案:

答案 0 :(得分:1)

我能发现的第一个错误是在你的合并功能结束时:

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,只要第一个列表的分区数少于第二个列表即可。