如何插入已排序的链表?

时间:2009-08-24 04:17:58

标签: c++ linked-list

  

可能重复:
  LinkedList “node jump”

我只需要按名称排序链表。我只能得到第1,第3,第5,......节点。我想不起这么远。我想成为一名C ++程序员,但如果我不明白这是他们的希望吗?此时作为学生,STL容器std::lists不是我的选择。您在列表函数中看到的是我正在尝试理解的内容。

list::node::node(const winery &winery) : item( winery.getName(), winery.getLocation(),
    winery.getAcres(), winery.getRating() ), nextByName( NULL ), nextByRating( NULL )
{

}

void list::insert(const winery& winery)
{
    node *current_node  = new node( winery ); // but came here and did this so it has new info!
    node *next_node     = NULL;
    node *tail_node     = current_node;

    if ( headByName == NULL ) // then we are here for the first item
    {       
        headByName   = current_node; // the list ptrs will have the first node's address. 
        headByRating = current_node; 
    }
    while ( headByName->nextByName != NULL )
    {
        headByName->nextByName = tail_node;
        tail_node = next_node;
        //next_node = current_node;
    }
    tail_node = new node( winery ); 
    headByName->nextByName = tail_node;
}

我可以使用的指针:

struct node
{
    winery  item;
    node *  nextByName;
    node *  nextByRating;
};

class list
{
    ...
private:
    node * headByName;
    node * headByRating;
};

4 个答案:

答案 0 :(得分:3)

你称这是一个双重链接列表,虽然你的每个节点都有两个链接,但这并不是大多数人在听到双链表时所想到的。由于你的两个链接显然彼此无关 - 没有人按字母顺序对酒厂进行评级 - 如果你不认为这是一个双重链表,那就更容易了。

当不需要更具体的订单时,插入链接列表的通常位置位于列表的末尾。执行此操作的步骤如下:

  1. 创建新节点。
  2. 找到插入新节点的位置(即列表末尾的最后一个节点)
  3. 更新最后一个节点的“下一个”指针以指向新节点。
  4. 当您插入列表的 middle 时,就像您的情况一样,那么还有另一个步骤:

    2.5。更新新节点的“下一个”指针。

    步骤通常不存在的原因是当在列表末尾插入时,新节点的“下一个”指针在构造新节点对象时已经为空。

    你已经找到了第一步。实际上,您已经了,因为您的代码实际上创建了两个新节点。一个存储在current_node中,另一个存储在tail_node中。摆脱第二个。

    步骤2是关于确定哪个节点应该是紧接在新节点之前的节点。按名称排序时,这将是您找到的第一个节点之前的节点,该节点在当前名称之后具有名称​​。您将不得不沿着列表走,可能会查看每个节点,直到您找到之后新节点名称的节点。当您沿着列表移动时,您将不得不在该节点之前跟踪哪个节点,因为一旦找到您正在寻找的节点,您将会不得不回溯。

    分别担心姓名和评级。不要试图一次解决这两个部分。一旦您按名称正确插入酒厂,然后复制该代码并将“名称”替换为“评级”。但是不要创建另一个节点对象。继续使用您之前创建的相同内容。

    在您完成此任务时,您是否绘制了任何带有箭头指向其他节点的节点图片?试试吧。你肯定已经在教科书或老师的黑板上看到了它。如果一个问题太大,你无法完全理解,那么就用一些东西来帮助你跟踪头脑中的事情。专业人士也这样做。由于每个节点都有多个指针,因此您应该标记指针或使用不同的颜色来命名和评级。

答案 1 :(得分:3)

当然有希望,我们都必须从某个地方开始! :)

首先,我必须指出我的学生使用的实施过程中的一种危险做法,并且通常会导致很多人摸不着头来发现问题:

while ( headByName->nextByName != NULL )
{
     headByName->nextByName = tail_node;
     tail_node = next_node;
     //next_node = current_node;
}

除非绝对必要,否则不要使用headByName之类的列表成员作为循环中的迭代变量。您应首先使用局部变量找到适当的节点,然后修改该节点。

那就是说,Rob Kennedy是对的,你应该分别处理名称和评级(换句话说,'纯'实现将有两个通用列表类的实例,不知道是什么' name'和'rating'是指),但是我假设上面列表,节点和函数的接口都是在赋值中给你的(如果不是,请忽略我的其余部分:))。

鉴于上述接口,我的方法如下:

void list::insert(const winery& winery)
{
    node* wineryNode = new node(winery);
    assert (wineryNode);

    // Find  a node in the list with a name greater than wineryNode's
    node* prevNode = NULL;
    node* searchNode = headByName; // Note: not using the list member itself to iterate but a local variable
    while (NULL != searchNode && 
        searchNode.winery.getName() < wineryNode.winery.getName())
    {
        // Keep iterating through the list until there are no more items, or the right node is found
        prevNode = searchNode;
        searchNode = searchNode->nextByName;
    }   

    /* At this point searchNode is either NULL 
       or it's name is greater than or equal to wineryNode's */

    // Check for the case where the list was empty, or the first item was what we wanted
    if (NULL == prevNode)
    {
        headByName = wineryNode;
    }
    else
    {
        // prevNode is not NULL, and it's Name is less wineryNode's
        prevNode-> nextByName = wineryNode;
    }
    wineryNode->nextByName = searchNode;    

    /*  Now you just need to insert sorted by rating using the same approach as above, except initialize searchNode to headByRating, 
    and compare and iterate by ratings in the while loop. Don't forget to reset prevNode to NULL */
}

答案 2 :(得分:0)

要成为双向链表,每个节点必须有一个指向该节点之前和之后的节点的指针。如果您愿意,也可以存储头尾节点,但这样做更方便个人使用,而不是满足双向链表的要求。

答案 3 :(得分:0)

我不确定我完全理解你的问题。仅从主题“如何插入已排序的链接列表?”我会做这样的事情(伪代码):

list::insert(Winery winery) {
    Winery node = getHeadNode();

    // winery comes before the head node
    if (winery.name < node.name) {
        // the old head node now goes after this new node
        // and this new node becomes the new head node
        winery.next = node;
        setHeadNode(winery);
        return;
    }

    // let's iterate over the rest of the nodes in the list
    Winery previous_node = node;
    node = node.next;
    while (node != NULL) {
        // we found our insertion point
        if (winery.name < node.name) {
            // insert our new node
            previous_node.next = winery;
            winery.next = node;
            return;
        }

        // insertion point not found, move to the next node and repeat
        previous_node = node;
        node = node.next;
    }

    // all elements visited, append our new element to the end of the list
    previous_node.next = winery;
    winery.next = NULL;
}

上述算法会将您的新节点插入列表中的适当位置,假设列表按名称排序。