شجرة فنويك

شجرة فنويك أو الشجرة الثنائية المفهرسة هي بنية معطيات يمكن فيها القيام بتعديل عنصر وحساب مجاميع البوادئ في جدول من القيم الحسابية بطريقة فعالة.

اقترح بوريس ريابكو عام 1989 بنية المعطيات هذه، ثم أضاف إليها مجموعة من التنقيحات عام 1992، ولكنها حظيت بشهرة واسعة تحت اسم شجرة فنويك بعدما نشر بيتر فنويك شرحاً مفصلاً عنها في ورقة بحثية عام 1994.

بالمقارنة مع مصفوفة أحادية البعد تستطيع شجرة فنويك الموازنة بين عملية تعديل العنصر وحساب مجاميع البودائ بطريقة أفضل. في مصفوفة أحادية البعد مكونة من  عنصر يمكن تخزين العناصر أو مجاميع البوادئ وليس كلا القيمتين. في الحالة الأولى (تخزين العناصر) يستهلك حساب مجاميع البوادئ وقتاً خطياً ، وفي الحالة الثانية (تخزين مجاميع البوادئ) يستهلك تخزين عنصر ما في المصفوفة وقتاً خطياً، أي أنه في كلا الحالتين تستهلك إحدى العمليتين وقتاً خطياً. تسمح شجرة فنويك بالقيام بكلا العمليتين خلال وقت لوغارتمي . يتم ذلك من خلال تمثيل عناصر المصفوفة كبنية شجرية، في هذه البنية الشجرية تُخزن في كل عقدة مجموع عناصر عقد الشجرة المتفرعة منها. تسمح هذه البنية الشجرية بتنفيذ العمليات المذكورة أعلاه عن طريق زيارة عدد من العقد مقداره .

كيفية العمل 

إن لشجرة فنويك بنيان شجري، وعلى الرغم من ذلك يتم تحقيق هذه الشجرة بشكل مضمّن في مصفوفة أحادية البعد بشكل مماثل لتحقيق شجرة الكومة. يتم حساب والد أو ابن عنصر ما عن طريق التلاعب ببتات ذلك العنصر. يحتوي كل عنصر من المصفوفة على مجموع مجال ما من الأعداد، وعن طريق إضافة مجاميع العقد الآباء وصولاً إلى جذر الشجرة يتم حساب مجموع كل المجالات المتتالية وبالتالي نحصل على مجموع كافة العناصر وصولاً إلى ذلك العنصر. عند تعديل قيمة ما من المصفوفة، يتم تعديل كل مجاميع المجالات المتضمنة ذلك العنصر من خلال القيام باجتياز عمودي للشجرة شبيه بالاجتياز المشروح سابقاً. يتم وضع مجاميع المجالات الجزئية ضمن عقد الشجرة المختلفة بطريقة يمكن من القيام بحساب مجاميع البوادئ وتعديل عناصر المجموعة بنفس التعقيد الزمني(تعقيد حالةٍ أسواً ).

التحقيق 
فيما يلي تحقيق لشجرة فنويك بلغة سي
#define LSB(i) ((i) & -(i)) // يقوم هذا الماكرو بتصفير جميع البتات عدا البت الأقل أهمية

int A[SIZE];

int sum(int i) // i تعيد هذه الدالة مجموع كافة العناصر من صفر وحتى العنصر
{
    int sum = 0;
    while (i > 0) 
        sum += A[i], i -= LSB(i);
    return sum;
}
 
void add(int i, int k) // تقوم هذه الدالة بإضافة (كي) إلى العنصر (آي)
{
    while (i < SIZE) 
        A[i] += k, i += LSB(i);
}

المراجع 

أشجار (بنى معطيات)
اختراعات روسية
اختراعات سوفيتية