2016-08-13 9 views
0

MaxHeapを使用して、配列内のk番目に小さい要素を見つける問題を解決しています。私のCコードは次のとおりです:Cの関数呼び出しにおけるセグメンテーションフォルト

#include <stdio.h> 
#include <stdlib.h> 
/** 
* @input A : Read only (DON'T MODIFY) Integer array 
* @input n1 : Integer array's (A) length 
* @input k : Integer 
* 
* @Output Integer 
*/ 
struct heap { 
    int *A; 
    int size; 
    int heapsize; 
}; 

void init_heap(struct heap*, int); 
void max_heapify(struct heap*, int); 
void add_heap(struct heap*, int); 
int extract_max(struct heap*); 
int get_max(struct heap*); 

int kthsmallest(const int* A, int n1, int k) { 
    struct heap* H = malloc(sizeof *H); 
    init_heap(H, k); 
    int i = 0; 
    for(i = 0; i < k; i++) { 
     add_heap(H, A[i]); 
    } 
    for(i = k; i < n1; i++) { 
     if (A[i] < get_max(H)) { 
      extract_max(H); 
      add_heap(H, A[i]); 
     } 
    } 
    return get_max(H); 
} 

//Initializes the heap array, heapsize and size 
void init_heap(struct heap* H, int n) { 
    H->A = malloc((n+1) * sizeof(int)); 
    H->heapsize = 0; 
    H->size = n; 
} 

//Makes the tree rooted at index i into a heap if the sub-trees at 2i and 2i+1 are heaps 
void max_heapify(struct heap* H, int index) { 
    int *arr = H->A; 
    int left = 2*index; 
    int right = 2*index+1; 
    int max = index; 
    if (left <= H->heapsize && arr[left] > arr[max]) max = left; 
    if (right <= H->heapsize && arr[right] > arr[max]) max = right; 
    if (max != index) { 
     int temp = arr[index]; 
     arr[index] = arr[max]; 
     arr[max] = temp; 
    } 
    max_heapify(H, max); 
} 

//Adds and element into the heap 
void add_heap(struct heap* H, int data) { 
    if(H->heapsize == H->size) { 
     return; 
    } 
    (H->heapsize)++; 
    int *arr = H->A; 
    arr[H->heapsize] = data; 
    int i = H->heapsize; 
    while(i > 1 && arr[i/2] < arr[i]) { 
     int temp = arr[i]; 
     arr[i] = arr[i/2]; 
     arr[i/2] = temp; 
     i = i/2; 
    } 
    //printf("Added %d\n", data); 
} 

int extract_max(struct heap* H) { 
    if (H->heapsize == 0) { 
     return -1; 
    } 
    int *arr = H->A; 
    int ret_val = arr[1]; 
    arr[1] = arr[H->heapsize]; 
    (H->heapsize)--; 
    max_heapify(H, 1); 
    //printf("Removed %d\n", ret_val); 
    return ret_val; 
} 

int get_max(struct heap* H) { 
    if (H->heapsize == 0) { 
     return -1; 
    } 
    return *((H->A)+1); 
} 

int main() { 
    int A[] = {8, 16, 80, 55, 32, 8, 38, 40, 65, 18, 15, 45, 50, 38, 54, 52, 23, 74, 81, 42, 28, 16, 66, 35, 91, 36, 44, 9, 85, 58, 59, 49, 75, 20, 87, 60, 17, 11, 39, 62, 20, 17, 46, 26, 81, 92}; 
    printf("Answer = %d\n", kthsmallest(A, 46, 9)); 
    return 0; 
} 

私はプログラムを実行すると、私はセグメンテーションフォールトを取得します。私はデバッグしようとしましたが、原因を見つけることができませんでした。

これは私のgdbの出力です:

Program received signal SIGSEGV, Segmentation fault. 
0x0000000100000cd8 in max_heapify (
    H=<error reading variable: Cannot access memory at address 0x7fff5f3ffff8>, index=<error reading variable: Cannot access memory at address 0x7fff5f3ffff4>) 
    at kthsmallest.c:49 
49 void max_heapify(heap* H, int index) { 

これは私のvalgrindの出力

==21378== Memcheck, a memory error detector 
==21378== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==21378== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info 
==21378== Command: ./a.out 
==21378== 
==21378== 
==21378== Process terminating with default action of signal 11 (SIGSEGV) 
==21378== Access not within mapped region at address 0x104002FF8 
==21378== at 0x100000DCE: max_heapify (kthsmallest.c:57) 
==21378== If you believe this happened as a result of a stack 
==21378== overflow in your program's main thread (unlikely but 
==21378== possible), you can try to increase the size of the 
==21378== main thread stack using the --main-stacksize= flag. 
==21378== The main thread stack size used in this run was 8388608. 

extract_max機能がmax_heapify関数を呼び出す際にセグメンテーションフォールトが起こっているです。

+0

あなたはシングルステップから何を得るのですか?期待どおりの値を返しますか?トレースはどうですか?スタック?エラーをチェックしないでください。 'malloc'から? – Olaf

+2

おそらく 'max_heapify'で' max_heapify'の呼び出しを止めないでください。 – BLUEPIXY

+0

@BLUEPIXYありがとう、私はそれを得て、max_heapifyは(最大!=インデックス)のときにのみ呼び出す必要があります。その再帰呼び出しをif条件に移動する必要があります。おそらく、スタックオーバーフローエラーでした。 – skankhunt42

答えて

1

max_heapifyは再帰的に呼び出し続けていたのでスタックオーバーフローエラーでした。 max_heapifyは、条件(max != index)がtrueの場合にのみ再帰的に呼び出す必要があります。条件付きで再帰呼び出しを上に移動し、コードが期待どおりに動作しています。

これは、最終的な正しい関数である:

void max_heapify(struct heap* H, int index) { 
    int *arr = H->A; 
    int left = 2*index; 
    int right = 2*index+1; 
    int max = index; 
    if (left <= H->heapsize && arr[left] > arr[max]) max = left; 
    if (right <= H->heapsize && arr[right] > arr[max]) max = right; 
    if (max != index) { 
     int temp = arr[index]; 
     arr[index] = arr[max]; 
     arr[max] = temp; 
     max_heapify(H, max); 
    } 
} 
関連する問題