2

Sorry if my English is bad, I speak Korean as mother tongue.

I've just learned about interval heap, and implementing interval heap in C.

My code should receive integers from input file, and if the value of read integer is positive, insert the value into interval heap, and if negative, minimum deleting operation should be executed. Besides, I want to print preorder/inorder traversal of interval heap on stdout in every insertion and deletion.

Here is the full code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct ipair_{
    int min;    //inserted first
    int max;
    int cnt;    //number of data in node
} interval;

typedef struct{
    interval * h;
    int size;
    int cnt;    //number of node
} *iheap;

typedef enum{
    NO_EMPTY=0,
    EMPTY_HEAP
} isEmpty;

void init_heap(iheap h, int n)
{   //initialize heap;
    n++;    // 1_based indices
    h->h = calloc(n, sizeof *h->h);
    h->size = n;
    h->cnt = 0;
}

//parent, child for 1_based_index
inline static int prt(int i)
{
    return i/2;
}

inline static int lch(int i)
{
    return i*2;
}

inline static int rch(int i)
{
    return i*2+1;
}

void insert_aux(iheap h, int cur, int data)
{   //insert to h->h[cur] in accordance with state of node;
    interval *current = h->h + cur;
    if((*current).cnt == 0)
    {
        (*current).min = data;
        (*current).cnt++;
    }
    //else if(h->h[h->cnt].cnt == 1)
    else if((*current).cnt == 1)
    {
        int prev = (*current).min;
        if(data < prev)
        {
            (*current).min = data;
            (*current).max = prev;
        }
        else
        {
            (*current).max = data;
        }
        (*current).cnt++;
    }
    else// if((*current).cnt >= 2)
    {
        current++;
        (*current).min = data;
        (*current).cnt++;
        h->cnt++;
    }
}

void insert(iheap h, int data)
{
    int cur = h->cnt + 1;
    int parent = prt(cur);
    if(data > h->h[parent].max)
    {
        while(data > h->h[parent].max)
        {
            if(cur == 1)
            {
                break;
            }
            //h->h[cur].max = h->h[parent].max;
            insert_aux(h, cur, h->h[parent].max);
            cur = parent;
            parent = prt(parent);
        }
        //h->h[cur].max = data;
        insert_aux(h, cur, data);
    }
    else if(data < h->h[parent].min)
    {
        while(data < h->h[parent].min)
        {
            if(cur == 1)
            {
                break;
            }
            //h->h[cur].min = h->h[parent].min;
            insert_aux(h, cur, h->h[parent].min);
            cur = parent;
            parent = prt(parent);
        }
        //h->h[cur].min = data;
        insert_aux(h, cur, data);

    }
    else
    {
        insert_aux(h, cur, data);
    }
    /*/
    interval *cur = h->h + h->cnt +1;   // +1 means 1_based indices
    interval *parent = h->h + (h->cnt+1)/2;
    if((*cur).cnt == 0)
    {
        (*cur).min = data;
        (*cur).cnt++;
    }
    //else if(h->h[h->cnt].cnt == 1)
    else if((*cur).cnt == 1)
    {
        int prev = (*cur).min;
        if(data < prev)
        {
            (*cur).min = data;
            (*cur).max = prev;
        }
        else
        {
            (*cur).max = data;
        }
        (*cur).cnt++;
    }
    else// if((*cur).cnt >= 2)
    {
        cur++;
        (*cur).min = data;
        (*cur).cnt++;
        h->cnt++;
    }
    /*/
}

void preorder(iheap h, int i)
{
    if(h->h[i].cnt)
    {
        if(h->h[i].cnt == 1)
        {
            printf(" (%d)", h->h[i].min);
        }
        else
        {
            printf(" (%d,%d)", h->h[i].min, h->h[i].max);
        }
        preorder(h, lch(i));
        preorder(h, rch(i));
    }
}

void printPreorder(iheap h)
{
    printf("preorder:");
    preorder(h, 1);
    putchar(10);
}

void inorder(iheap h, int i)
{
    if(h->h[i].cnt)
    {
        inorder(h, lch(i));
        if(h->h[i].cnt == 1)
        {
            printf(" (%d)", h->h[i].min);
        }
        else
        {
            printf(" (%d,%d)", h->h[i].min, h->h[i].max);
        }
        inorder(h, rch(i));
    }
}

void printInorder(iheap h)
{
    printf("inorder:");
    inorder(h, 1);
    putchar(10);
}

isEmpty deleteMin(iheap h, int * buf)
{
    int p, last, cur, temp;
    _Bool rch_lower;
    if(!h->cnt)
    {
        if(h->h[0].cnt == 0)
        {
            return EMPTY_HEAP;
        }
        else if(h->h[0].cnt == 1)
        {
            *buf = h->h[0].min;
            h->h[0].cnt--;
            return NO_EMPTY;
        }
    }
    *buf = h->h[0].min;
    last = h->cnt + 1;
    p = h->h[last].min;
    h->h[last].cnt--;
    if(h->h[last].cnt == 0)
    {
        h->cnt--;
    }
    cur = 1;
    while(1)
    {
        if(!h->h[lch(cur)].cnt)
        {
            break;
        }
        int minch;
        rch_lower = 0;
        if(h->h[rch(cur)].cnt == 0)
        {
            minch = h->h[lch(cur)].min;
        }
        else
        {
            if(h->h[lch(cur)].min > h->h[rch(cur)].min)
            {
                rch_lower = 1;
                minch = h->h[rch(cur)].min;
            }
            else
            {
                minch = h->h[lch(cur)].min;
            }
        }
        if(!(p>minch))
        {
            break;
        }
        h->h[cur].min = minch;
        if(rch_lower)
        {
            cur = rch(cur);
        }
        else
        {
            cur = lch(cur);
        }
        if(p > h->h[cur].max)
        {
            temp = p;
            p = h->h[cur].max;
            h->h[cur].max = temp;
        }
    }
    h->h[cur].min = p;
    return NO_EMPTY;
}

int main(int argc, char * * argv)
{
    int * buf;
    int cnt;
    int temp;

    iheap h = malloc(sizeof *h);

    if(argc != 2)
    {
        printf("usage: %s <filename>", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *fp = NULL;
    if((fp = fopen(argv[1], "r")) == NULL)
    {
        //file open failed
        fprintf(stderr, "file open error\n");
        exit(EXIT_FAILURE);
    }

    //file open succeeded

    for(cnt=0; ; cnt++)
    {
        if((fscanf(fp, "%i", &temp)) == EOF)
        {
            break;
        }
    }
    rewind(fp);
    buf = calloc(cnt, sizeof *buf);
    for(int i=0; i<cnt; i++)
    {
        fscanf(fp, "%i", buf+i);
    }

    init_heap(h, cnt);

/*/
    for(int i=0; i<cnt; i++)
    {
        printf("%d ", buf[i]);
    }
    putchar(10);
/*/

    for(int i=0; i<cnt; i++)
    {
        if(buf[i] < 0)
        {
            if(deleteMin(h, &temp))
            {
                puts("공백 트리");
            }
            else
            {
                printPreorder(h);
                printInorder(h);
            }
        }
        else
        {
            insert(h, buf[i]);
            printPreorder(h);
            printInorder(h);
        }
    }

/*/
    for(int i=1; i<cnt+1; i++)
    {
        printf("%d-%d ", h->h[i].min, h->h[i].max);
    }
    putchar(10);
/*/


    return 0;
}

It seemingly works well with short input, but long input like
2 40 3 17 4 32 4 12 3 11 5 10 6 30 4 10 5 11 5 9 4 7 8 8 7 9 15 15 -1 results in strange output:

...
(skipped)
...
preorder: (2,40) (3,17) (4,12) (4,10) (5,11) (3,11) (5,9) (4,7) (4,32) (5,10) (8,8) (7,9) (15,30) (10)
inorder: (4,10) (4,12) (5,11) (3,17) (5,9) (3,11) (4,7) (2,40) (8,8) (5,10) (7,9) (4,32) (10) (15,30)
preorder: (2,40) (3,17) (4,12) (4,10) (5,11) (3,11) (5,9) (4,7) (4,32) (5,10) (8,8) (7,9) (15,30) (10) (15) (1041,0) (1919247474,841490490)
inorder: (4,10) (4,12) (5,11) (3,17) (5,9) (3,11) (4,7) (2,40) (8,8) (5,10) (7,9) (4,32) (10) (15,30) (1041,0) (15) (980575588,741615648)
preorder: (3,40) (3,17) (4,12) (4,10) (5,11) (4,15) (5,9) (7,11) (4,32) (5,10) (8,8) (7,9) (15,30) (10)
inorder: (4,10) (4,12) (5,11) (3,17) (5,9) (4,15) (7,11) (3,40) (8,8) (5,10) (7,9) (4,32) (10) (15,30)

I cannot figure out what logic I wrote is wrong. It's buggy behavior, but no compile error / segmentation fault detected.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
k9wan
  • 45
  • 3
  • OT: don't write `(*cur).min`, rather write `cur->min`. It's the same thing, but the first form isn't used other than by beginners that don't know better. – Jabberwocky Nov 04 '21 at 12:44
  • As for your problem, check if none of your array indexes (like `i` in `h->h[i]` are out of bounds by adding some checking code. – Jabberwocky Nov 04 '21 at 12:45

0 Answers0