这是关于Stack Overflow的第一个问题所以请保持温和。提前感谢您的任何回复,您似乎真的知道您在机器峰值时所做的事情。
我一直在构建一个Linked List工具包模板,我需要做的最后一个补充是sort()函数和merge()函数。
这是我的节点结构的私有成员变量:
struct node
{
Item data; // the variable containing the data in the node.
node* next; // the pointer to the next node in the list.
node( Item _data, node* _next = NULL ) // constructor to build a node when data or the link is already known
{
data = _data;
next = _next;
}
};
node* head;
这是我的简单排序函数,用于测试列表是否按升序排序:
template <class Item>
bool List<Item>::sorted( )
{
node* cursor; // allocate a node pointer for traversal
for ( cursor = head; cursor != NULL; cursor = cursor->next) // loop from head until NULL
if ( cursor->data > cursor->next->data )
return false; // if we ever find that the data in a node is greater than the data in the next node, return false
return true; // if we reach this point, the list is in ascending order
}
如果我能够递归地解决sort()函数,我写了这个函数作为简单基本情况的一种方法,唉我已经能够实现这个目标了。注意:我对迭代解决方案同样满意,就像我使用递归解决方案一样。
现在; merge()函数(请注意,如果我可以进行排序工作,断言将被替换为对sort()的两次调用!)
template <class Item>
List<Item> List<Item>::merge(List<Item>& list1, List<Item>& list2)
{ // libraries used: <algorithm> for sort() and <cassert> for assert();
if ( list1.head == NULL ) // if the first list is empty, just return the second list
return list2;
if ( list2.head == NULL ) // if the second list is empty, just return the first list
return list1;
assert ( sorted() && otherList.sorted() ); // if this assertion is false, the function will not work.
List<Item> newList;
node* cursor1 = head;
node* cursor2 = otherList.head;
while ( cursor1 != NULL && cursor2 != NULL )
{
if (cursor1 == NULL)
{
while (cursor2 != NULL)
{
newList.headInsert(cursor2->data);
cursor2 = cursor2->next;
}
}
if (cursor2 == NULL)
{
while (cursor1 != NULL)
{
newList.headInsert(cursor1->data);
cursor1 = cursor1->next;
}
}
if (cursor1->data < cursor2->data)
{
newList.headInsert(cursor1->data);
cursor1 = cursor1->next;
}
if (cursor2->data < cursor1->data)
{
newList.headInsert(cursor2->data);
cursor2 = cursor2->next;
}
else
if (cursor1->data == cursor2->data)
{
newList.headInsert(cursor1->data);
newList.headInsert(cursor2->data);
cursor1 = cursor1->next;
cursor2 = cursor2->next;
}
}
clear();
head = newList.head;
}
排序功能是我真正迷失的地方。我在这个网站上看了很多回答的问题,但没有发现任何我真正想要的东西。如果可能的话,我希望有一个声明为这样的函数
void List<Item>::sort( )
如果可能的话,如果有人能向我解释如何实现我的merge()函数,我会更加感激
void List<Item>::merge(List<Item>& L2)
我认为如果我可以将merge作为一个函数实现,而不是将合并的节点分配给一个新的List,它会很棒。它可以很容易地使用另一个List并基本上将它们合并到我的主列表中,就像这样
myList.merge(otherList);
我确实知道有很多类似的问题已经在这个网站上单独回答了,所以请不要只是把我链接到另一个问题,因为我很有机会看到它并空手而归(因为至少这个问题)。问题是,即使在仔细研究了问题和答案后,我仍然无法找到问题的答案。除非我有充分的理由,否则我不想模仿别人的代码。这对我来说更像是一次学习练习,我只是在编写最佳方法时阻止了这一点。我很乐意上传任何其他代码块,或者在我的思考过程中添加更多评论,而且批评非常受欢迎。任何格式提示也将受到赞赏。
此致
一位充满激情的新手编码器
表示rclgdr
template <class Item>
void List<Item>::sort( )
{
if ( head == NULL || head->next == NULL ) // the list is empty or contains only one node, so it doesn't require sorting
return;
node* cursor = head; // the cursor will be used for traversal
node* smallest = head; // this will always point to the node with the lowest data value
node* was_smallest = head; // tthis will point to the smallest data if a smaller value is found by the cursor
node* back = head; // this is a previous pointer, pointing at the node behind the cursor
node* temp; // I always declare a temporary cursor just in case, it will be returned to heap anyway
while ( cursor != NULL ) //cursor has originated at the head, and will go until it reaches NULL
{
if ( cursor->data < smallest->data ) // compare the data to the current smallest data
{
was_smallest = back; // if the smallest was trumped by the cursor's data, set was_smallest to smallest
smallest = cursor; // smallest is where the cursor is pointing
}
back = cursor; // always point back at where the cursor is
cursor = cursor->next; // THEN move the cursor, back is pointing at the previous node
}
if ( head != smallest ) // if the head is not the smallest (it SHOULD be!)
{
was_smallest->next = head; // link was_smallest to the new head, essentially making it the new head
temp = head->next; // first use of temp, point it after the head
head->next = smallest->next; // after the head ( not TEMP! ) is linked from the new head (smallest)
smallest->next = temp; // link smallest to the head's link
}
// I believe I need a recursive call here I think (head != smallest) is the base case?
}
template <class Item>
void List<Item>::merge(List<Item>& otherList)
{ // libraries used: <algorithm> for sort() and <cassert> for assert();
if ( list1.head == NULL ) // if the first list is empty, just return the second list
return list2;
if ( list2.head == NULL ) // if the second list is empty, just return the first list
return list1;
assert ( sorted() && otherList.sorted() ); // if this assertion is false, the function will not work.
List<Item> newList;
node* cursor1 = head;
node* cursor2 = otherList.head;
while ( cursor1 != NULL && cursor2 != NULL )
{
if (cursor1 == NULL)
{
while (cursor2 != NULL)
{
newList.headInsert(cursor2->data);
cursor2 = cursor2->next;
}
}
if (cursor2 == NULL)
{
while (cursor1 != NULL)
{
newList.headInsert(cursor1->data);
cursor1 = cursor1->next;
}
}
if (cursor1->data < cursor2->data)
{
newList.headInsert(cursor1->data);
cursor1 = cursor1->next;
}
if (cursor2->data < cursor1->data)
{
newList.headInsert(cursor2->data);
cursor2 = cursor2->next;
}
else
if (cursor1->data == cursor2->data)
{
newList.headInsert(cursor1->data);
newList.headInsert(cursor2->data);
cursor1 = cursor1->next;
cursor2 = cursor2->next;
}
}
clear()
head = newList.head;
}
答案 0 :(得分:0)
您需要关注的第一件事是您的解决方案的高级描述。看起来你想要进行合并排序,为此步骤是:
你提到你希望sort
成为一个成员函数,所以就这样做:
void List::sort(); // ignoring template arguments here
对于实现,首先需要将列表拆分为两个,而不假设您知道正确的大小,您可以通过创建新列表(本地)并将每个其他节点从此节点移动到另一个节点来分成两半名单。此时,您有两个可以递归排序的列表,然后您可以调用merge
以同样的方式,您可以将merge
实现为获取其他列表的成员函数:
void List::merge(List & other);
请注意界面中的一些更改。第一个是如果你想进行就地操作,那么返回列表的副本是没有意义的,你什么也不返回(调用者已经有了对象)或者你可以返回对此列表的引用。
答案 1 :(得分:0)
递归地将列表拆分为子列表以进行排序是低效的。 HP / Microsoft STL std :: list :: sort使用一个指向节点的n个指针数组,其中array [i]是一个大小为2 ^ i的列表(除了数组[n-1]可以更大),加上一个临时指针到一个节点。节点被&#34;合并&#34;一次一个地进入数组。合并一个所有节点,然后合并该数组以创建排序列表。
您还可以使用指向节点的4个指针(2&#34;源&#34;,2&#34;目标&#34; poitners)和子列表大小计数(1)实现更传统的自下而上排序,2,4,8,...,直到&gt; =列表的大小)
古代示例C代码。该数组是静态的,但如果将此代码转换为类,则该数组将是类成员。请注意有关NODE.next和LIST.first的注释,该注释用于简化附加到空列表的操作。一些STL代码使用类似的方法,但您可以添加代码来检查空列表处理,而不需要关于next的假设,并且首先是结构的第一个成员(这意味着它们具有与结构相同的地址)。
#define NUMLISTS 32 /* number of lists */
typedef unsigned long long UI64;
/* MergeLists() casts an instance of LIST to NODE */
/* and uses NODE.next as the equivalent of LIST.first */
typedef struct _NODE{
struct _NODE * next; /* must be first member of NODE */
UI64 data;
}NODE, *PNODE;
typedef struct _LIST{
NODE *first; /* must be first member of LIST */
}LIST, *PLIST;
/*----------------------------------------------------------------------*/
/* data */
/*----------------------------------------------------------------------*/
static LIST aList[NUMLISTS]; /* array of lists */
/*----------------------------------------------------------------------*/
/* SortList */
/*----------------------------------------------------------------------*/
void SortList(LIST *pList)
{
NODE * pNode;
LIST mList; /* merged list */
int i;
if(pList == NULL) /* check for null ptr */
return;
/* merge nodes into aList[] */
while(NULL != (pNode = GetFirstNode(pList))){
MergeNode(pNode);
}
/* find 1st non empty aList[] */
for(i = 0; (i < NUMLISTS) && (aList[i].first == NULL); i++);
if(i >= NUMLISTS){ /* if all empty */
pList->first = NULL; /* return null list */
return;
}
pList->first = aList[i].first; /* plist = aList[i] */
aList[i].first = NULL; /* clear aList[i] (optional) */
for(i++; i < NUMLISTS; i++){ /* merge remaining aList[] */
if(aList[i].first != NULL){
MergeLists(&mList, &aList[i], pList);
pList->first = mList.first;
}
}
}
/*----------------------------------------------------------------------*/
/* MergeNode merge a node into the array of lists */
/*----------------------------------------------------------------------*/
void MergeNode(NODE *pNode)
{
LIST sList; /* source list */
LIST mList; /* merged list */
int i;
if(pNode == NULL) /* return if null ptr */
return;
sList.first = pNode; /* src list = node */
/* merge into array */
for(i = 0; (i < NUMLISTS) && (aList[i].first != NULL); i++){
MergeLists(&mList, &aList[i], &sList);
sList.first = mList.first;
}
if(i == NUMLISTS) /* update array */
i--;
aList[i].first = sList.first;
}
/*----------------------------------------------------------------------*/
/* MergeLists dst = merge(src1, src2) */
/*----------------------------------------------------------------------*/
void MergeLists(LIST *plDst, LIST *plSrc1, LIST *plSrc2)
{
NODE *pDst, *pSrc1, *pSrc2; /* node ptrs */
pDst = (NODE *)plDst; /* treat list same as node */
pSrc1 = GetFirstNode(plSrc1); /* init ptrs to nodes */
pSrc2 = GetFirstNode(plSrc2);
while(1){
if(pSrc2->data < pSrc1->data){ /* if src2 < src1 */
pDst->next = pSrc2;
pDst = pDst->next;
/* if end of src2, dst = rest of src1 */
if(NULL == (pSrc2 = GetFirstNode(plSrc2))){
pSrc1->next = plSrc1->first;
pDst->next = pSrc1;
plSrc1->first = NULL;
break;
}
} else { /* src1 <= src2 */
pDst->next = pSrc1;
pDst = pDst->next;
/* if end of src1, dst = rest of src2 */
if(NULL == (pSrc1 = GetFirstNode(plSrc1))){
pSrc2->next = plSrc2->first;
pDst->next = pSrc2;
plSrc2->first = NULL;
break;
}
}
}
}
/*----------------------------------------------------------------------*/
/* GetFirstNode */
/*----------------------------------------------------------------------*/
NODE * GetFirstNode(LIST * pSrc)
{
NODE * pNode;
if(pSrc == NULL) /* return if null ptr */
return NULL;
pNode = pSrc->first; /* get node */
if(pNode != NULL){
pSrc->first = pNode->next; /* advance list ptr */
pNode->next = NULL; /* reset node ptr */
}
return pNode;
}