删除链接列表中的连续元素

时间:2016-11-06 12:26:39

标签: c algorithm linked-list

给出了链表

的以下定义
typedef struct elemento {
    int inf;
    struct elemento *next;
} lista;

我正在尝试创建一个函数

  

lista * SeekAndDestroy(lista * p,int k);

给定列表* p和正整数k(在列表上搜索),第一个连续元素序列的总和恰好是k,并从列表中消除这些元素。

我的尝试:

lista *SeekAndDestroy(lista *p, int k) {
    lista *a, *nuovo;
    int x = 0;

    a = (lista *)malloc(sizeof(lista));
    a->inf = p->inf;
    nuovo = a;
    p = p->next;

    while (p != NULL) {
        if (p->next != NULL) {
            if ((p->inf + p->next->inf) == k) {
                if (x != 1) {
                    p = p->next->next;
                    x = 1;
                    continue;
                }
            }
        }
        nuovo->next = (lista *)malloc(sizeof(lista));
        nuovo = nuovo->next;
        nuovo->inf = p->inf;
        p = p->next;
    }
    nuovo->next = NULL;
    return a;
}

我的解决方案有两个主要问题:
1)最多删除两个连续元素而不是更多 2)如果要删除的项目是前两项,则该功能不起作用 我怎么解决这个问题?感谢

4 个答案:

答案 0 :(得分:1)

假设您的数字都是非负数,那么您可以使用更高效的算法。您只需在列表中运行两个指针ptrAptrB,保持包含元素的总和。

如果总和不是你需要什么,你可以做两件事之一。首先,如果当前总和小于所需数量,则通过推进ptrB将下一个元素带入数组。

如果您当前的总和超过您的需要,您可以通过推进ptrA来取出您范围内的第一个元素。当然,这两种操作都应该调整当前的范围总和。这里有一个边缘案例,如果目前只有一个项目,你就不想这样做。

不言而喻,如果当前范围总和等于您所需的范围,您只需删除该范围并退出。

就伪代码而言,它将类似于:

def delExact(list, desiredSum):
    # Check non-empty and start range.

    if list is empty:
        return
    ptrA = list.first
    ptrB = ptrA
    rangeSum = ptrA.value

    # Continue until match found

    while rangeSum is not equal to desiredSum:
        # Select add-another or remove-first.

        if ptrA == ptrB, or rangeSum < desiredSum:
            # Need to bring another in, returning if list exhausted.

            ptrB = ptrB.next
            if ptrB == null:
                return
            rangeSum = rangeSum + ptrB.value
        else:
            # Need to remove one.

            rangeSum = rangeSum - ptrA.value
            ptrA = ptrA.next

    # If we exit the loop, we've found a sum match.
    # Hence we need to delete ptrA through ptrB inclusive.

然而,如果允许使用负数,那么双指针方法就会崩溃,因为你实际上并不知道后来的元素会有什么影响。

在这种情况下,你基本上必须对所有可能性进行详尽的搜索,这基本上归结为:

for each element in list:
    for each possible segment from that element on:
        check and act on summed data

这实际上更像是一个英语代表,这种野兽的伪代码将是:

def delExact(list, desiredSum):
    # For each list element.

    ptrA = list.first
    while ptrA is not null:
        # For each possible segment starting at that element.

        segmentSum = 0
        ptrB = ptrA
        while ptrB is not null:
            add ptrB.value to segmentSum

            # Delete segment if sum matches, then return.

            if segmentSum is equal to desiredSum:
                # Here we delete from ptrA through ptrB inclusive.
                return

            # Otherwise, keep adding elements to segment.

            ptrB = ptrB.next

        # No matching segment, move on to next element.

        ptrA = ptrA.next

    # No matching segment at any element, just return.

使用 这些算法将解决您只删除两个元素的问题。

在列表开头删除的问题是简单地识别该事实(ptrA == list.first)并确保在这种情况下调整first指针。这是链表处理中的标准边缘情况,可以实现为:

def deleteRangeInclusive(list, ptrA, ptrB):
    # Adjust list to remove ptrA/ptrB segment,
    #   allowing for possibility ptrA may be the head.

    if ptrA == list.first:
        list.first = ptrB.next
    else:
        beforeA = list.first
        while beforeA.next != ptrA:
            beforeA = beforeA.next
        beforeA.next = ptrB.next

    # Now we can safely remove the ptrA-ptrB segment.

    while ptrA != ptrB:
        tempA = ptrA
        ptrA = ptrA.next
        delete element tempA
    delete element ptrB

答案 1 :(得分:1)

现在,让我们忘记链表和指针和东西。说,我们必须解决给定数组的问题。我们可以这样做吗?当然!

for (int i = 0; i < array.length; ++i) {
    for (int j = i; j < array.length; ++j) {
        int sum = getRangeSum(array, i, j);
        if (sum != k) continue;

        // construct new array and return
    }
}

此代码可以进一步优化,但现在让它保持简单。因此,在链表中,可以使用类似的方法。删除部分也很简单。您可以保留一个变量来跟踪 i 的上一个节点。我们称之为 iParent 。现在,我们可以将[i,j]段删除为iParent->next = j->next

显然,您需要考虑一些极端情况,例如,如果找不到这样的段,或者段是否从链表的开头开始等。

答案 2 :(得分:1)

这是我写的一个函数,用于解决您面临的两个问题以及任何其他边界条件:

list* Seek_Destroy(list* head, int target){
    if(head == NULL)
        return NULL;
    list* temp = head;
    bool find_complete = false;

    list *prev = temp;
    //Loop for iterating until list is complete or target sum is found.
    while( !find_complete){
        //Create a pointer for loop calculations
        list* sum_loop = temp;
        //Initialize sum to 0
        int sum =0;
        //Loop for checking whether the sum is equal to the target
        while(sum <= target && sum_loop->next!= NULL){
            //Keep adding the sum
            sum += sum_loop->inf;

            if(sum == target){
                //Set the flag for exiting outer loop
                find_complete = true;
                //Test whether head of the list is included in the sum
                if (temp == head){
                    //Make head point to the struct after the last element included in the sum loop
                    head = sum_loop->next;
                    //Delete and free memory
                    while(temp!= sum_loop){
                        list* del = temp;
                        temp = temp->next;
                        free(del);
                    }
                }else {
                    //Set the next pointer of previous element  of the list to point after the last element included in the sum loop
                    prev->next= sum_loop->next;
                    //Delete and free memory
                    while(temp!= sum_loop){
                        list* del = temp;
                        temp = temp->next;
                        free(del);
                    }
                }           
            break;
            }
            //Increment the pointer for the sum calculation         
            sum_loop = sum_loop->next;
        } 
        prev = temp;
        //Make temp point to next element in the list
        temp = temp->next;
        //IF entire list is traversed set the flag to true
        if (temp ==NULL){
            find_complete = true;
        }       
    }

    return head;
}

答案 3 :(得分:0)

我这样解决了:

Lista *Distruggi(Lista *p, int k) {
    Lista *n = NULL, *nuova = NULL;
    int z = 0;
    for (Lista *i = p; i != NULL && z != 1; i = i->next) {
        for (Lista *j = i; j != NULL; j = j->next) {
            int sum = somma(i, j);
            if (sum != k) continue;

            n = (Lista *)malloc(sizeof(Lista));
            n->inf = p->inf;
            p = p->next;
            nuova = n;

            while (p != i) {
                nuova->next = (Lista *)malloc(sizeof(Lista));
                nuova = nuova->next;
                nuova->inf = p->inf;
                p = p->next;
            }

            while (j != NULL) {
                nuova->next = (Lista *)malloc(sizeof(Lista));
                nuova = nuova->next;
                nuova->inf = j->inf;
                j = j->next;
            }
            z = 1;
            break;
       }
    }
    if (z == 0) return p;//NO CHANGE
    else {//CHANGE
        nuova->next = NULL;
        return n;
    }
}
相关问题