انتقل إلى المحتوى

كدسة

من ويكيبيديا، الموسوعة الحرة
(بالتحويل من مكدس (بنية بيانات))
كدسة مع 5 عمليات دفع متتابعة يليها 5 عمليات نزع متتابعة.

الكُدسة أو الكَدسة (الجمع: أكداس وكُدسات وكَدسات)، في علم الحاسوب، نوع بيانات مجرد يُمثِّل جماعة[الإنجليزية] متسلسلة لها منفذ واحد لإدخال البيانات وإخراجها بعمليتين رئيستين: الدفع[ا][عر 1] والنزع[ب]. في الأولى، يُضاف عنصر جديد على قمة ما يوجد مسبقًا، وفي الثانية يُزال العنصر الموجود في أعلى [ج] الكدسة أو قمتها. أما قَعْر الكدسة[د] فهو موضع أول عنصر يُضاف إليها، وهو آخر عنصر يُنزع منها قبل أن تصبح فارغة.

لترتيب الإدخال في الكدسة أهمية خاصة، وهو: الداخل أخيرًا يخرج أولًا[ه]. يعني هذا أن إخراج العناصر في أعلى الكدسة سهل بسيط، أما إخراج أي عنصر يقع تحت عنصر القمة فيتطلب إخراج العناصر التي تقع فوقه كلها.

يُمكن أن تنشأ الكدسة بقائمة متصلة مع مؤشر يدل على قمة الكدسة. ويُمكن أيضًا أن تكون ذات مقاسٍ ثابت، فلو تجاوزته كمية البيانات قيل عندها أن الكدسة قد فاضت أو طفحت[و].

التسمية

[عدل]

يذكر معجم لسان العرب في مادة (ك د س): «الكُدْس والكَدْس: العَرَمَة مِنَ الطَّعَامِ وَالتمر وَالدراهِمِ ونحو ذلك، والجمع أَكداس». ويتصرَّف فعلها الثلاثي المُجرَّد من الباب الثاني: «كَدَسَ يَكْدِس كَدْساً».[عر 5] وفي المعجم المدرسي أن: «الكُدْس هو المجتمع من كل شيء»، ويذكر مزيده الثلاثي بحرفين (تكدَّس): «تكدس الحصيد: جُعِل كُدْسًا. وتكدَّست الأشياء: تراكمت وازدحمت وتجمع بعضها فوق بعض».[عر 6]

وفي المعاجم التقنية ورد لفظ (كدسة) من غير ضبطٍ كما في (معجم مصطلحات المعلوماتية) الصادر عن الجمعية العلمية السورية للمعلوماتية.[عر 7] ومن الأسماء الأخرى لهذه البنية أيضًا: المَكْدَس والكَوْمة والرُّكام،[عر 8] والرَّصَّة[عر 9] والصف القائم.[عر 10]

نبذة تاريخية

[عدل]

بدأ ظهور مفهوم الكدسة في علم الحاسوب بدءًا من سنة 1946م، عندما استعمل آلان تورنغ مصطلحي دَفَن ونقَّب[ز] للإشارة إلى استدعاء دالة وإعادة قيمة منها.[1] أُنجِزت الكدسة وعمليتا الدفع والنزع مسبقًا في حاسوب زد4 الذي صنعه كونراد سوزه سنة 1945م.[2]

اقترح فريدريش باور وكلاوس ساميلسون في أثنا عملهما في جامعة ميونخ التقنية فكرة الكدسة سنة 1955، وسمياها «المستدعي العملياتي»[ح]،[ألم 1] وسجلا براءة اختراع فيها سنة 1957م.[وب-ألم 1][3] حصل ساميلسون سنة 1988، بعد وفاة باور (1980م)، على جائزة رواد الحاسوب[الإنجليزية] التي يقدمها معهد مهندسي الكهرباء والإلكترونيات.[وب-ألم 2]

مبدأ العمل

[عدل]
تمثيل مُبسَّط للكدسة وللعمليات الرئيسة عليه

الكدسة قائمة خطية تجري كل العمليات عليها، من إدراج عناصر جديدة فيها وإزالة العناصر منها والوصول إلى عناصر فيها، على أحد نهايتي القائمة. وهي تختلف بذلك على القوائم الخطية الأخرى: الرتل، الذي تجري عمليات الإدخال على أحد نهايته، والإزالة على النهاية الأخرى، والرتل المزدوج[الإنجليزية]: الذي تجري عمليات الإدخال والإخراج على نهايتيه.[4]

ويتفق (معجم أكسفورد لعلم الحاسوب) مع هذا التعريف فالكَدْسة وفقًا له: قائمة خطية تُنجز العمليات على عنصرها، وصولًأ وإدراجًا وحذفًا، من أحد طرفيها الذي يُسمَّى قمةً، والوصول إلى عناصرها أو إدراجها وحذفها.[5] وتُعرِّف الطبعة الرابعة من (معجم الحاسبات) الصادر عن مجمع اللغة العربية بالقاهرة الكدسة بأنها: «طريقة لتخزين البيانات في هيكل مدخله هو مخرجه، فيكون آخر بيان دخولًا هو أولها خروجًا»[عر 9]

كدسة الصحون تشبه في مبدأ عملها كدسة البيانات: لا يُمكن إزالة الصحون أو إضافتها إلا من رأس الكدسة.

تشبه الكدسة المحوسبة كدسة الصحون ذات النابض في المقاهي،[6] وفيها تُوضع الصحون النظيفة الجاهزة للاستعمال على قمة الكدسة دافعة الصحون الموجودة مسبقًا إلى الأسفل. عند إزالة الصحن الموجود في القمة يحل محله الصحن الموجود تحته مباشرة.

للكدسة عمليتان رئيستان:[عر 11]

  • الدفع: أي إضافة عنصر على أعلى الكدسة.
  • النزع، وتُسمَّى أيضًا القَطْف: أي سحب عنصرٍ من أعلى الكدسة.

يُمكن أيضًا قراءة قيمة العنصر في أعلى الكدسة من غير تعديلها، وتُسمَّى هذه العملية وَصْوصة[الإنجليزية].[7] لا تعد الوَصْوصة عملية رئسية لأنها تشمل عمليتن رئيستين: نزع القيمة لقراءتها ثُمَّ دفعها للكدسة.

يُسمَّى العنصر الأعلى في الكدسة رأسها، وهو العنصر الذي سيُزال لو أجريت عملية نزعٍ، ويُسمى العنصر تحته العنصر التالي بعد الرأس[ط]، والذي يليه الثالث بدءًا من الرأس[ي] وهكذا وصولًا لقعر الكدسة، وهو أبعد العناصر فيها عن الرأس.[8]

إذا كانت الكدسة فارغة، أي لا عناصر فيها فهي في حالة غَيْض[يا]، وعندها لا يُمكِن إجراء عمليتي النزع والوَصْوصة لعدم وجود أي عنصر، أما إذا كانت الكدسة ممتلئة على آخرها، فهي في حالة فيض أو طَفْح، ولا يُمكن عندها إجراء عملية الدفع.

التنجيز

[عدل]
مخطط صنفي لكدسة بلغة النمذجة الموحَّدة.

يمكن تنجيز الكدسة بسهولة باستعمال مصفوفة أو قائمة متصلة مع اعتبارها حالة خاصة من القوائم المتصلة. ما يجعل بنية البيانات كدسةً ليس ليس طريقة تنجيزها بل طريقة التعامل معها: يُمكِن للمستخدم نزع عتصر من رأسها أو دفع عنصر إليها.

للكدسة 3 دوال رئيسة: دالة الدفع: لإضافة عنصر لرأس للكدسة ويُمرَّر لها العنصر الذي يُراد إضافته ولا تُعيد أي قمية، ودالة النزع: لإخراج عنصر من رأس الكدسة وهي تعيد العنصر المنزوع، ودالة التحقق من فراغها وتعيد قيمة منطقية: صائب للدالة على فراغ الكدسة، وباطل للدلالة على عدم فراغها. إذا كان للكدسة قد محدد فيمكن كتابة دالة تعيد القد.[9]

بمصفوفة

[عدل]

البنية والسلوك

[عدل]

يُمكن أن تُستعمل مصفوفة لتنجيز كدسة محدودة القد. يؤدي الموقع الأول في المصفوفة،أي الموقع الذي تكون إزاحته صفرية array[0]، دور قعر الكدسة، سيخزن هذا الموقع أول عنصر يُدفَع إلى المصفوفة وهو الهنصر الأخير الذي سيزال قبل الوصول لحالة الغيض. يلزم تتبع قد الكدسة بمتغير يُسمَّى الرأس يحفظ عدد العناصر المدفوعة للكدسة، وبما أن إزاحة العنصر الأول صفرية، فإن الرأس يُشير إلى فهرس المصفوفة الذي سيدفع إليه العنصر التالي.

يُوصَف هيكل بيانات الكدسة المبنية بمصفوفة وإجرائية استبدائها كما يأتي:

تضيف إجرائية الدفع عنصرًا لرأس الكدسة وتزيد قيمتها بمقدار واحد بعد التأكد من عدم حصول فيض (طَفح):[وب-إنج 1]

صورة مُحرَّكة لعمليات دفع متتالية لكدسة مبنية بمصفوفة من حالة الغيض إلى حالة الفيض (الطفح).

أما إجرائية النزع فتنقص الرأس بمقدار واحد بعد التأكد من عدم حصول غيض (فراغ الكدسة)، ثُم تعيد العنصر الذي كان سابقًا في رأس الكدسة.[وب-إنج 1]

صورة مُحرَّكة لعمليات نزع متتالية لكدسة مبنية بمصفوفة من حالة الامتلاء الكامل إلى حالة الغيض.

يُمكن استعمال مصفوفة ديناميكية لجعل قد الكدسة ينمو ويتقلص حسب الحاجة. يُحسن هذا من كفاءة التنجيز لأن إضافة عنصر لكدسة مبنية بمصفوفة ديناميكية أو إزالته من نهاية الكدسة يستهلك زمنًا قدره O(1).

بلغات برمجة مختلفة

[عدل]

الكدسة المبنية بمصفوفة ودوالها مُنجَزة بلغة سي++:[وب-إنج 1]

# include <iostream>
using namespace std;

class myStack {
    
    // array to store elements
    int *arr;       
    
    // maximum size of stack
    int capacity;   
    
    // index of top element
    int top;

public:

    // constructor
    myStack(int cap) {
        capacity = cap;
        arr = new int[capacity];
        top = -1;
    }

    // push operation
    void push(int x) {
        if (top == capacity - 1) {
            cout << "Stack Overflow\n";
            return;
        }
        arr[++top] = x;
    }

    // pop operation
    int pop() {
        if (top == -1) {
            cout << "Stack Underflow\n";
            return -1;
        }
        return arr[top--];
    }

    // peek (or top) operation
    int peek() {
        if (top == -1) {
            cout << "Stack is Empty\n";
            return -1;
        }
        return arr[top];
    }

    // check if stack is empty
    bool isEmpty() {
        return top == -1;
    }

    // check if stack is full
    bool isFull() {
        return top == capacity - 1;
    }
};

int main() {
    myStack st(4);

    // pushing elements
    st.push(1);
    st.push(2);
    st.push(3);
    st.push(4);

    // popping one element
    cout << "Popped: " << st.pop() << "\n";

    // checking top element
    cout << "Top element: " << st.peek() << "\n";

    // checking if stack is empty
    cout << "Is stack empty: " << (st.isEmpty() ? "Yes" : "No") << "\n";

    // checking if stack is full
    cout << "Is stack full: " << (st.isFull() ? "Yes" : "No") << "\n";

    return 0;
}

الكدسة المبنية بمصفوفة مُنجَزة بلغة جافا:[وب-إنج 1]

import java.util.Arrays;

class myStack {

    // array to store elements
    private int[] arr;

    // maximum size of stack
    private int capacity;

    // index of top element
    private int top;

    // constructor
    public myStack(int cap) {
        capacity = cap;
        arr = new int[capacity];
        top = -1;
    }

    // push operation
    public void push(int x) {
        if (top == capacity - 1) {
            System.out.println("Stack Overflow");
            return;
        }
        arr[++top] = x;
    }

    // pop operation
    public int pop() {
        if (top == -1) {
            System.out.println("Stack Underflow");
            return -1;
        }
        return arr[top--];
    }

    // peek (or top) operation
    public int peek() {
        if (top == -1) {
            System.out.println("Stack is Empty");
            return -1;
        }
        return arr[top];
    }

    // check if stack is empty
    public boolean isEmpty() {
        return top == -1;
    }

    // check if stack is full
    public boolean isFull() {
        return top == capacity - 1;
    }
}

public class Main {
    public static void main(String[] args) {
        myStack st = new myStack(4);

        // pushing elements
        st.push(1);
        st.push(2);
        st.push(3);
        st.push(4);

        // popping one element
        System.out.println("Popped: " + st.pop());

        // checking top element
        System.out.println("Top element: " + st.peek());

        // checking if stack is empty
        System.out.println("Is stack empty: " +
                            (st.isEmpty() ? "Yes" : "No"));

        // checking if stack is full
        System.out.println("Is stack full: " +
                            (st.isFull() ? "Yes" : "No"));
    }
}

الكدسة المبنية بمصفوفة مُنجَزة بلغة بايثون:[وب-إنج 1]

class myStack:
    # constructor
    def __init__(self, cap):
        self.capacity = cap
        self.arr = [0] * self.capacity
        self.top = -1

    # push operation
    def push(self, x):
        if self.top == self.capacity - 1:
            print("Stack Overflow")
            return
        self.top += 1
        self.arr[self.top] = x

    # pop operation
    def pop(self):
        if self.top == -1:
            print("Stack Underflow")
            return -1
        val = self.arr[self.top]
        self.top -= 1
        return val

    # peek (or top) operation
    def peek(self):
        if self.top == -1:
            print("Stack is Empty")
            return -1
        return self.arr[self.top]

    # check if stack is empty
    def isEmpty(self):
        return self.top == -1

    # check if stack is full
    def isFull(self):
        return self.top == self.capacity - 1

if __name__ == "__main__":
    st = myStack(4)

    # pushing elements
    st.push(1)
    st.push(2)
    st.push(3)
    st.push(4)

    # popping one element
    print("Popped:", st.pop())

    # checking top element
    print("Top element:", st.peek())

    # checking if stack is empty
    print("Is stack empty: ", "Yes" if st.isEmpty() else "No")

    # checking if stack is full
    print("Is stack full: ", "Yes" if st.isFull() else "No")

بقائمة متصلة

[عدل]

يُمكن أن تُبنى الكدسة بقائمة متصلة، وتكون عندها مؤشر يُشير إلى رأس القائمة[يب] وقد يُضاف إليها عداد لتتبع عدد العناصر في القائمة أي قد الكدسة. تبنى الكدسة بقائمة متصلة كما يأتي:[وب-إنج 2]

تُنجَز عمليتي الدفع والنزع على رأس الكدسة، ولا يُمكن نظريًا أن يحصل فيض (طَفح) لأن قد الكدسة غير ثابت، لكن استهلاك كامل الذاكرة يؤدي لفيض الكدسة.[وب-إنج 2]

صورة مُحرَّكة لعمليات دفع متتالية لكدسة مبنية بقائمة متصلة.
صورة مُحرَّكة لعمليات نزع متتالية لكدسة مبنية بقائمة متصلة.

بلغات برمجة مختلفة

[عدل]

الكدسة المبنية بقائمة متصلة ودوالها مُنجَزة بلغة سي++:[وب-إنج 2]

#include <bits/stdc++.h>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node(int new_data) {
        this->data = new_data;
        this->next = nullptr;
    }
};

class Stack {
    Node* head;

public:
    Stack() { this->head = nullptr; }

    bool isEmpty() {
        return head == nullptr;
    }

    void push(int new_data) {
        Node* new_node = new Node(new_data);
        if (!new_node) {
            cout << "\nStack Overflow";
        }
        new_node->next = head;
        head = new_node;
    }

    void pop() {
        if (this->isEmpty()) {
            cout << "\nStack Underflow" << endl;
        } else {
            Node* temp = head;
            head = head->next;
            delete temp;
        }
    }

    int peek() {
        if (!isEmpty())
            return head->data;
        else {
            cout << "\nStack is empty";
            return INT_MIN;
        }
    }
};

int main() {
    Stack st;

    st.push(11);
    st.push(22);
    st.push(33);
    st.push(44);

    cout << "Top element is " << st.peek() << endl;

    cout << "Removing two elements..." << endl;
    st.pop();
    st.pop();

    cout << "Top element is " << st.peek() << endl;

    return 0;
}

الكدسة المبنية بقائمة متصلة مُنجَزة بلغة جافا:[وب-إنج 2]

// Java program to implement a stack using singly linked
// list

// Class representing a node in the linked list
class Node {
    int data;
    Node next;
    Node(int new_data) {
        this.data = new_data;
        this.next = null;
    }
}

// Class to implement stack using a singly linked list
class Stack {

    // Head of the linked list
    Node head;

    // Constructor to initialize the stack
    Stack() { this.head = null; }

    // Function to check if the stack is empty
    boolean isEmpty() {
      
        // If head is null, the stack is empty
        return head == null;
    }

    // Function to push an element onto the stack
    void push(int new_data) {
      
        // Create a new node with given data
        Node new_node = new Node(new_data);

        // Check if memory allocation for the new node
        // failed
        if (new_node == null) {
            System.out.println("\nStack Overflow");
            return;
        }

        // Link the new node to the current top node
        new_node.next = head;

        // Update the top to the new node
        head = new_node;
    }

    // Function to remove the top element from the stack
    void pop() {
      
        // Check for stack underflow
        if (isEmpty()) {
            System.out.println("\nStack Underflow");
            return;
        }
        else {
          
            // Assign the current top to a temporary
            // variable
            Node temp = head;

            // Update the top to the next node
            head = head.next;

            // Deallocate the memory of the old top node
            temp = null;
        }
    }

    // Function to return the top element of the stack
    int peek() {
      
        // If stack is not empty, return the top element
        if (!isEmpty())
            return head.data;
        else {
            System.out.println("\nStack is empty");
            return Integer.MIN_VALUE;
        }
    }
}

// Driver code
public class Main {
    public static void main(String[] args)
    {
        // Creating a stack
        Stack st = new Stack();

        // Push elements onto the stack
        st.push(11);
        st.push(22);
        st.push(33);
        st.push(44);

        // Print top element of the stack
        System.out.println("Top element is " + st.peek());

        // removing two elemements from the top
  		System.out.println("Removing two elements...");
        st.pop();
        st.pop();

        // Print top element of the stack
        System.out.println("Top element is " + st.peek());
    }
}

الكدسة المبنية بقائمة متصلة مُنجَزة بلغة بايثون:[وب-إنج 2]

# Java program to implement a stack using singly linked
# list

# Class representing a node in the linked list
class Node:
    def __init__(self, new_data):
        self.data = new_data
        self.next = None

# Class to implement stack using a singly linked list
class Stack:
    def __init__(self):

        # head of the linked list
        self.head = None

    # Function to check if the stack is empty
    def is_empty(self):

        # If head is None, the stack is empty
        return self.head is None

    # Function to push an element onto the stack
    def push(self, new_data):

        # Create a new node with given data
        new_node = Node(new_data)

        # Check if memory allocation for the new node failed
        if not new_node:
            print("\nStack Overflow")
            return

        # Link the new node to the current top node
        new_node.next = self.head

        # Update the top to the new node
        self.head = new_node

    # Function to remove the top element from the stack
    def pop(self):

        # Check for stack underflow
        if self.is_empty():
            print("\nStack Underflow")
        else:

            # Assign the current top to a temporary variable
            temp = self.head

            # Update the top to the next node
            self.head = self.head.next

            # Deallocate the memory of the old top node
            del temp

    # Function to return the top element of the stack
    def peek(self):

        # If stack is not empty, return the top element
        if not self.is_empty():
            return self.head.data
        else:
            print("\nStack is empty")
            return float('-inf')

# Creating a stack
st = Stack()

# Push elements onto the stack
st.push(11)
st.push(22)
st.push(33)
st.push(44)

# Print top element of the stack
print("Top element is", st.peek())

# removing two elemements from the top
print("Removing two elements...");
st.pop()
st.pop()

# Print top element of the stack
print("Top element is", st.peek())

انظرأيضًا

[عدل]

ملاحظات

[عدل]
  1. ^ (بالإنجليزية: push)
  2. ^ (بالإنجليزية: pop)[عر 2]
  3. ^ (بالإنجليزية: top)[عر 3]
  4. ^ (بالإنجليزية: bottom)، يُعرِّف معجم الجمعية السورية للمعلوماتية بأنه: موضع العنصر الذي استغرق مكوثه في الكدسة أطول مدة.[عر 4]
  5. ^ (بالإنجليزية: last in, first out) اختصارًا LIFO
  6. ^ (بالإنجليزية: overflow)
  7. ^ (بالإنجليزية: bury & unbury)
  8. ^ (بالألمانية: Operationskeller)، (بالإنجليزية: Operational cellar)
  9. ^ (بالإنجليزية: Next to top)
  10. ^ (بالإنجليزية: Third from top)
  11. ^ (بالإنجليزية: underflow)
  12. ^ (بالإنجليزية: head)

المراجع

[عدل]

فهرس الإحالات

[عدل]
المنشورات
بالعربية
بالألمانية
  1. ^ Langmaack (2014), p. 21-23.
بالإنجليزية
  1. ^ [a] Carpenter (1977), p. 271-272.
    [b] Carpenter (1986), p. 10.
  2. ^ Blaauw (1997), p. 552.
  3. ^ Bauer (2001), p. 29-40.
  4. ^ Knuth (1997), p. 239.
  5. ^ Butterfield (2016), p. 551.
  6. ^ [a] Ball (1978), p. 4.
    [b] Cormen (2009), p. 232-233.
  7. ^ Horowitz (1984), p. 67.
  8. ^ Knuth (1997), p. 241.
  9. ^ Seidl (2015), p. 180.
الوب
بالألمانية
  1. ^ DE1094019B, Friedrich Ludwig Bauer & Klaus Samelson, "Verfahren zur automatischen Verarbeitung von kodierten Daten und Rechenmaschine zur Ausuebung des Verfahrens", published 1960-12-01 
  2. ^ "IEEE-Computer-Pioneer-Preis". Technische Universität München (بالألمانية). 1 Jan 1989. Archived from the original on 2017-11-07. Retrieved 2017-11-07.
بالإنجليزية
  1. ^ ا ب ج د ه "Stack using Array". Geeksforgeeks (بالإنجليزية). Archived from the original on 2025-11-25. Retrieved 2025-02-08.
  2. ^ ا ب ج د ه "Implement a stack using singly linked list". Geeksforgeeks (بالإنجليزية). Archived from the original on 2025-07-10. Retrieved 2025-02-10.

ثبت المراجع

[عدل]
المقالات المُحكَّمة

بالألمانية

بالإنجليزية
الكتب
بالعربية
بالإنجليزية