উন্নত বিষয়

সি প্রোগ্রামিং উদাহরণ (C Examples) - Computer Science

395

উন্নত C প্রোগ্রামিং বিষয়গুলো বিভিন্ন দিক থেকে জটিল এবং গভীর। নিচে কিছু গুরুত্বপূর্ণ উন্নত বিষয় উল্লেখ করা হলো:

1. ডেটা স্ট্রাকচার এবং অ্যালগরিদম

  • লিঙ্কড লিস্ট, স্ট্যাক, কিউ: কিভাবে এই ডেটা স্ট্রাকচারগুলো তৈরি এবং ব্যবহার করতে হয়।
  • গাছ (Tree) এবং গ্রাফ (Graph): বাইনারি ট্রি, AVL ট্রি, গ্রাফ ট্রাভার্সাল (DFS, BFS)।
  • অ্যালগরিদম: সোরটিং (Quick sort, Merge sort) এবং সার্চিং অ্যালগরিদম (Binary search)।

2. মেমোরি ব্যবস্থাপনা

  • ডাইনামিক মেমোরি বরাদ্দ: malloc(), calloc(), realloc(), free() এর উন্নত ব্যবহার।
  • মেমোরি লিক ও এর প্রতিরোধ: মেমোরি লিক শনাক্ত করা এবং প্রতিরোধের জন্য টুল ব্যবহার।

3. মাল্টিথ্রেডিং

  • থ্রেডস এবং প্রসেসেস: থ্রেড তৈরি, পরিচালনা এবং সমন্বয় করা।
  • মিউটেক্স এবং সেমাফোর: মাল্টিথ্রেডেড প্রোগ্রামে ডেটা সুরক্ষা।

4. ফাইল ব্যবস্থাপনা

  • বাইনারি এবং টেক্সট ফাইল: ফাইল খুলা, পড়া, লেখা এবং বন্ধ করা।
  • ফাইল ইন্ডেক্সিং: বড় ফাইলের জন্য কার্যকরী তথ্য সংরক্ষণ পদ্ধতি।

5. ফাংশন পয়েন্টার এবং কলব্যাক

  • ফাংশন পয়েন্টার: ফাংশনকে আর্গুমেন্ট হিসেবে পাস করা এবং ফলস্বরূপ হিসেবে ব্যবহার করা।
  • কলব্যাক ফাংশন: বিভিন্ন কার্যকরী সিস্টেম তৈরি করতে।

6. পোর্টেবল কোড এবং স্ট্যান্ডার্ডাইজেশন

  • ANSI C স্ট্যান্ডার্ড: কোড পোর্টেবিলিটি এবং কম্পাইলার নিরপেক্ষতার জন্য।

7. প্রিপ্রসেসর ডিরেক্টিভ

  • ম্যাক্রো এবং কন্ডিশনাল কম্পাইলিং: উন্নত প্রিপ্রসেসর নির্দেশনা ব্যবহার।

8. নেটওয়ার্কিং

  • সকেট প্রোগ্রামিং: TCP/IP এবং UDP ব্যবস্থায় যোগাযোগ।

9. ডিবাগিং এবং টেস্টিং

  • ডিবাগিং টুলস: gdb, valgrind ইত্যাদি ব্যবহার করা।
  • ইউনিট টেস্টিং: কোডের ভিন্ন অংশের কার্যকারিতা পরীক্ষা করা।

10. অপারেটিং সিস্টেমের সাথে যোগাযোগ

  • সিস্টেম কল: অপারেটিং সিস্টেমের বিভিন্ন ফাংশন ও সিস্টেম কল ব্যবহার করা।

এই বিষয়গুলো C প্রোগ্রামিংয়ে গভীরতা আনার জন্য গুরুত্বপূর্ণ এবং এগুলোর অধ্যয়ন করলে আপনি উন্নত পর্যায়ে পৌঁছাতে পারবেন। কোনো নির্দিষ্ট বিষয় সম্পর্কে আরও বিস্তারিত জানার আগ্রহ থাকলে জানান!

Content added By

মাল্টিথ্রেডিং এবং সিঙ্ক্রোনাইজেশন হলো কম্পিউটার প্রোগ্রামিংয়ের গুরুত্বপূর্ণ দুটি ধারণা, যা সমান্তরাল প্রসেসিং এবং ডেটা সুরক্ষা নিশ্চিত করতে ব্যবহৃত হয়। মাল্টিথ্রেডিংয়ের মাধ্যমে একাধিক থ্রেড একই সময়ে কাজ করতে পারে, আর সিঙ্ক্রোনাইজেশন নিশ্চিত করে যে একাধিক থ্রেড নিরাপদভাবে একসাথে কাজ করছে এবং ডেটা সংঘর্ষ এড়াচ্ছে।

মাল্টিথ্রেডিং

মাল্টিথ্রেডিং একটি প্রোগ্রামিং কৌশল যেখানে একাধিক থ্রেড একই প্রোগ্রামে একটি সময়ে কার্যকর হয়। একটি থ্রেড হলো একটি প্রসেসের সবচেয়ে ছোট ইউনিট, যা একসঙ্গে কাজ করার জন্য ব্যবহৃত হয়। মাল্টিথ্রেডিংয়ের মাধ্যমে CPU-এর সম্পদ আরও কার্যকরভাবে ব্যবহার করা যায়।

মাল্টিথ্রেডিংয়ের সুবিধা:

  1. প্রদর্শন বৃদ্ধি: একাধিক থ্রেড ব্যবহার করে CPU এর সময়কে সঠিকভাবে ব্যবহার করা যায়, যা কর্মক্ষমতা বাড়ায়।
  2. উত্তরদায়িতা: UI থ্রেড এবং ব্যাকগ্রাউন্ড থ্রেড আলাদা করে ব্যবহার করা যায়, যা অ্যাপ্লিকেশনকে আরও উত্তরদায়ী করে তোলে।
  3. সম্পদ ভাগাভাগি: থ্রেডগুলি একই প্রক্রিয়ার সম্পদ ব্যবহার করতে পারে, যা মেমোরি ব্যবস্থাপনা সহজ করে।

উদাহরণ:

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

void* thread_function(void* arg) {
    printf("Thread %d is running.\n", *((int*)arg));
    return NULL;
}

int main() {
    pthread_t threads[5];
    int thread_args[5];

    for (int i = 0; i < 5; i++) {
        thread_args[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, (void*)&thread_args[i]);
    }

    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    return 0;
}

সিঙ্ক্রোনাইজেশন

সিঙ্ক্রোনাইজেশন হলো একটি কৌশল যা মাল্টিথ্রেডেড প্রোগ্রামে ডেটার নিরাপত্তা নিশ্চিত করে। যখন একাধিক থ্রেড একটি অভিন্ন রিসোর্সে (যেমন একটি ভেরিয়েবল বা ডেটা স্ট্রাকচার) কাজ করে, তখন ডেটা সংঘর্ষ এড়ানোর জন্য সিঙ্ক্রোনাইজেশন প্রয়োজন।

সিঙ্ক্রোনাইজেশনের পদ্ধতি:

  1. মিউটেক্স (Mutex): একটি লক যা নিশ্চিত করে যে এক সময়ে একটি মাত্র থ্রেড একটি নির্দিষ্ট রিসোর্সে প্রবেশ করতে পারে।
  2. সেমাফোর (Semaphore): একটি গণনা করা লক যা একাধিক থ্রেডকে একটি নির্দিষ্ট সংখ্যক রিসোর্সে প্রবেশ করতে দেয়।
  3. কন্ডিশন ভেরিয়েবল (Condition Variable): থ্রেডগুলোর মধ্যে সিঙ্ক্রোনাইজেশনের জন্য ব্যবহৃত হয়, যাতে একটি থ্রেড অপেক্ষা করতে পারে অন্য একটি থ্রেডের সিগন্যালের জন্য।

উদাহরণ: মিউটেক্সের ব্যবহার

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

pthread_mutex_t lock;  // মিউটেক্স লক ডিফাইন করা
int shared_counter = 0; // শেয়ার্ড কাউন্টার

void* thread_function(void* arg) {
    pthread_mutex_lock(&lock);  // লক নেয়া
    for (int i = 0; i < 100000; i++) {
        shared_counter++; // শেয়ার্ড কাউন্টার বাড়ানো
    }
    pthread_mutex_unlock(&lock); // লক মুক্ত করা
    return NULL;
}

int main() {
    pthread_t threads[10];
    pthread_mutex_init(&lock, NULL); // মিউটেক্স ইনিশিয়ালাইজ

    for (int i = 0; i < 10; i++) {
        pthread_create(&threads[i], NULL, thread_function, NULL);
    }

    for (int i = 0; i < 10; i++) {
        pthread_join(threads[i], NULL);
    }

    printf("Final counter value: %d\n", shared_counter); // ফাইনাল কাউন্টার মান
    pthread_mutex_destroy(&lock); // মিউটেক্স ধ্বংস করা
    return 0;
}

সারাংশ

  • মাল্টিথ্রেডিং: একাধিক থ্রেডের মাধ্যমে সমান্তরাল কার্য সম্পাদনের কৌশল, যা CPU এর সম্পদের কার্যকর ব্যবহার নিশ্চিত করে।
  • সিঙ্ক্রোনাইজেশন: একাধিক থ্রেডের মধ্যে নিরাপদ ডেটা শেয়ারিং নিশ্চিত করতে ব্যবহৃত হয়, যাতে ডেটা সংঘর্ষ এড়ানো যায়।

মাল্টিথ্রেডিং এবং সিঙ্ক্রোনাইজেশন একসাথে কাজ করে সি প্রোগ্রামগুলিতে কার্যকারিতা বৃদ্ধি এবং নিরাপত্তা নিশ্চিত করতে সহায়তা করে।

Content added By

নেটওয়ার্ক প্রোগ্রামিং হলো একটি পদ্ধতি যা কম্পিউটার নেটওয়ার্কের মাধ্যমে ডেটা বা সংযোগ প্রতিষ্ঠার জন্য ব্যবহৃত হয়। এটি সিস্টেমগুলোর মধ্যে যোগাযোগ প্রতিষ্ঠা করার এবং ডেটা বিনিময় করার জন্য বিভিন্ন প্রযুক্তি, প্রোটোকল, এবং প্রোগ্রামিং ভাষার ব্যবহার অন্তর্ভুক্ত করে। নেটওয়ার্ক প্রোগ্রামিংয়ের মৌলিক ধারণা ও উপাদানগুলো নিচে আলোচনা করা হলো।

মৌলিক ধারণা

ক্লায়েন্ট এবং সার্ভার:

  • নেটওয়ার্ক প্রোগ্রামিংয়ে সাধারণত দুটি প্রধান অংশ থাকে: ক্লায়েন্ট এবং সার্ভার। ক্লায়েন্ট হল সেই প্রোগ্রাম যা সার্ভারের সাথে যোগাযোগ করার চেষ্টা করে, এবং সার্ভার হল সেই প্রোগ্রাম যা ক্লায়েন্টের অনুরোধ গ্রহণ করে এবং প্রতিক্রিয়া দেয়।

প্রোটোকল:

  • নেটওয়ার্কের মধ্যে যোগাযোগের জন্য নির্দিষ্ট নিয়মাবলী বা প্রক্রিয়া। সাধারণ প্রোটোকলগুলো হলো:
    • TCP/IP (Transmission Control Protocol/Internet Protocol): এটি মূলত ইন্টারনেটে ডেটা ট্রান্সফারের জন্য ব্যবহৃত হয় এবং ক্লায়েন্ট-সার্ভার অ্যাপ্লিকেশন তৈরি করতে ব্যবহৃত হয়।
    • UDP (User Datagram Protocol): এটি একটি দ্রুত যোগাযোগের প্রোটোকল, কিন্তু ডেটার নির্ভরযোগ্যতা নিশ্চিত করে না।

সোকে́টস:

  • সোকেট হলো একটি প্রোগ্রামিং অবজেক্ট যা নেটওয়ার্কে যোগাযোগের জন্য ব্যবহৃত হয়। এটি একটি পোর্ট এবং একটি আইপি ঠিকানা দ্বারা চিহ্নিত হয় এবং ক্লায়েন্ট ও সার্ভারের মধ্যে ডেটা বিনিময়ের জন্য একটি চ্যানেল তৈরি করে।

আইপি ঠিকানা:

  • ইন্টারনেটে বা নেটওয়ার্কে একটি ডিভাইস চিহ্নিত করতে ব্যবহৃত সংখ্যা। এটি ডিভাইসগুলোর মধ্যে যোগাযোগের জন্য গুরুত্বপূর্ণ।

পোর্ট নম্বর:

  • এটি সার্ভারে চলমান একটি নির্দিষ্ট পরিষেবার সাথে সংযুক্ত। উদাহরণস্বরূপ, HTTP সার্ভারের জন্য সাধারণত পোর্ট 80 ব্যবহার হয়।

নেটওয়ার্ক প্রোগ্রামিংয়ের মৌলিক পদক্ষেপ

সার্ভার তৈরি:

  • একটি সার্ভার তৈরি করতে হয় যা নির্দিষ্ট পোর্টে অপেক্ষা করে ক্লায়েন্টের সংযোগের জন্য।

ক্লায়েন্ট তৈরি:

  • ক্লায়েন্ট তৈরি করতে হয়, যা সার্ভারের আইপি ঠিকানা এবং পোর্ট নম্বর ব্যবহার করে সংযোগ স্থাপন করে।

সংযোগ স্থাপন:

  • ক্লায়েন্ট সার্ভারের সাথে সংযোগ স্থাপন করে এবং সার্ভার ক্লায়েন্টের অনুরোধ গ্রহণ করে।

ডেটা বিনিময়:

  • ক্লায়েন্ট এবং সার্ভারের মধ্যে ডেটা পাঠানো এবং গ্রহণ করা হয়।

সংযোগ বন্ধ করা:

  • কাজ শেষ হলে, সংযোগ বন্ধ করতে হয়।

উদাহরণ: সি তে নেটওয়ার্ক প্রোগ্রামিং

সার্ভার কোড:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // সার্ভার সোকেট তৈরি
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    // সোকেট বৈশিষ্ট্য সেট করা
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // সোকেট বাইন্ড করা
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    // সংযোগ গ্রহণ করা
    if (listen(server_fd, 3) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Server is listening on port %d\n", PORT);
    new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
    
    // ক্লায়েন্টের বার্তা গ্রহণ করা
    read(new_socket, buffer, 1024);
    printf("Message from client: %s\n", buffer);

    // ক্লায়েন্টকে বার্তা পাঠানো
    char *response = "Hello from server";
    send(new_socket, response, strlen(response), 0);
    
    // সোকেট বন্ধ করা
    close(new_socket);
    close(server_fd);
    
    return 0;
}

ক্লায়েন্ট কোড:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *message = "Hello from client";
    char buffer[1024] = {0};

    // সোকেট তৈরি
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("Socket creation error \n");
        return -1;
    }

    // সার্ভারের ঠিকানা সেট করা
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    
    // সার্ভারের IP ঠিকানা সেট করা
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        printf("Invalid address/ Address not supported \n");
        return -1;
    }

    // সার্ভারের সাথে সংযোগ স্থাপন
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("Connection Failed \n");
        return -1;
    }

    // সার্ভারে বার্তা পাঠানো
    send(sock, message, strlen(message), 0);
    printf("Message sent to server\n");

    // সার্ভার থেকে প্রতিক্রিয়া গ্রহণ
    read(sock, buffer, 1024);
    printf("Response from server: %s\n", buffer);

    // সোকেট বন্ধ করা
    close(sock);
    
    return 0;
}

সারসংক্ষেপ

  • মাল্টিথ্রেডিং: একাধিক থ্রেডের মাধ্যমে সমান্তরাল কার্য সম্পাদন।
  • সিঙ্ক্রোনাইজেশন: একাধিক থ্রেডের মধ্যে নিরাপদ ডেটা শেয়ারিং।
  • সোকেট: নেটওয়ার্কে যোগাযোগের জন্য একটি ইন্টারফেস।
  • ক্লায়েন্ট এবং সার্ভার: একে অপরের সাথে যোগাযোগকারী প্রোগ্রাম।

নেটওয়ার্ক প্রোগ্রামিং কম্পিউটারের বিভিন্ন ডিভাইসের মধ্যে যোগাযোগ এবং ডেটা বিনিময়ে ব্যবহৃত হয়, যা আধুনিক প্রযুক্তির একটি অপরিহার্য অংশ।

Content added By

C প্রোগ্রামিংয়ে কম্পাইল টাইম এবং রানটাইম ত্রুটি দুটি গুরুত্বপূর্ণ ধারণা। এগুলো ত্রুটি শনাক্তকরণ এবং হ্যান্ডলিংয়ের ক্ষেত্রে প্রভাব ফেলে। নিচে উভয়ের সংজ্ঞা, উদাহরণ এবং হ্যান্ডলিংয়ের পদ্ধতি আলোচনা করা হলো।

কম্পাইল টাইম ত্রুটি

সংজ্ঞা: কম্পাইল টাইম ত্রুটি (Compile-time Errors) হলো সেসব ত্রুটি যা প্রোগ্রাম কম্পাইল করার সময় ঘটে। এই ত্রুটিগুলো সাধারণত সিনট্যাক্স বা টাইপ ত্রুটির কারণে হয়, যার ফলে কম্পাইলার প্রোগ্রামটি তৈরি করতে অক্ষম হয়।

উদাহরণ:

#include <stdio.h>

int main() {
    int num;
    printf("Enter a number: ");
    scanf("%d", num);  // ত্রুটি: num-এর ঠিকানার পয়েন্টার ব্যবহার করা হয়নি
    return 0;
}

এখানে scanf() ফাংশনের দ্বিতীয় আর্গুমেন্টে num পরিবর্তনশীলের ঠিকানা &num ব্যবহার করা উচিত। এটা একটি কম্পাইল টাইম ত্রুটি।

হ্যান্ডলিং:

  • ত্রুটি সংশোধন: সিনট্যাক্স ত্রুটির কারণে প্রোগ্রামটি কম্পাইলার দ্বারা শনাক্ত করা হয় এবং প্রোগ্রামিং ভুলগুলি সংশোধন করে এই ত্রুটি সমাধান করতে হবে।
  • ট্রেসিং: কম্পাইলার ত্রুটির সঠিক অবস্থান এবং কারণ প্রদর্শন করে, যা প্রোগ্রামারের জন্য সহায়ক।

রানটাইম ত্রুটি

সংজ্ঞা: রানটাইম ত্রুটি (Runtime Errors) হলো সেসব ত্রুটি যা প্রোগ্রামটি চলাকালীন সময়ে ঘটে। এটি সাধারণত লজিক্যাল ত্রুটি, ডেটা ইনপুট ত্রুটি, মেমোরি ত্রুটি, বা ডিভাইসের সাথে যোগাযোগের সমস্যার কারণে ঘটে।

উদাহরণ:

#include <stdio.h>

int main() {
    int num1, num2;
    printf("Enter two numbers: ");
    scanf("%d %d", &num1, &num2);
    
    // Zero Division Error
    int result = num1 / num2;  // যদি num2 শূন্য হয়, তাহলে রানটাইম ত্রুটি হবে
    printf("Result: %d\n", result);
    return 0;
}

এখানে যদি num2 শূন্য হয়, তাহলে রানটাইম সময়ে "Division by zero" ত্রুটি ঘটবে।

হ্যান্ডলিং:

C তে রানটাইম ত্রুটি হ্যান্ডলিংয়ের জন্য প্রচলিত উপায় হল:

ইনপুট যাচাইকরণ: ইনপুট মান যাচাই করা।

if (num2 == 0) {
    printf("Error: Division by zero is not allowed.\n");
    return 1; // ত্রুটি কোড রিটার্ন করা
}

লজিক্যাল ত্রুটি সংশোধন: লজিক্যাল ত্রুটিগুলি শনাক্ত এবং সংশোধন করতে কোড পর্যালোচনা করা।

মেমোরি ত্রুটি হ্যান্ডলিং: মেমোরি বরাদ্দের পরে সেটি সফলভাবে হয়েছে কিনা পরীক্ষা করা।

int *arr = (int *)malloc(size * sizeof(int));
if (arr == NULL) {
    printf("Memory allocation failed.\n");
    return 1;
}

উপসংহার

কম্পাইল টাইম এবং রানটাইম ত্রুটি হ্যান্ডলিং প্রোগ্রামিংয়ের একটি গুরুত্বপূর্ণ অংশ। কম্পাইল টাইম ত্রুটিগুলো সাধারণত কোড সংশোধনের মাধ্যমে সমাধান করা হয়, যেখানে রানটাইম ত্রুটিগুলো চলমান অবস্থায় ডেটা যাচাইকরণের মাধ্যমে হ্যান্ডল করা হয়। দুই ধরনের ত্রুটির প্রতি সতর্ক থাকলে প্রোগ্রামিংয়ে কার্যকর এবং নির্ভরযোগ্য কোড লেখা সম্ভব।

Content added By

ডেটা স্ট্রাকচার হলো ডেটা সংগঠিত করার একটি পদ্ধতি, যা কম্পিউটারে ডেটা সংরক্ষণ ও পরিচালনা করার জন্য ব্যবহৃত হয়। এখানে আমরা কিছু সাধারণ ডেটা স্ট্রাকচার যেমন লিংকড লিস্ট, স্ট্যাক, কিউ, এবং ট্রি নিয়ে আলোচনা করব।

১. লিংকড লিস্ট (Linked List)

লিংকড লিস্ট হলো একটি ডেটা স্ট্রাকচার যা একটি সিরিজ নোড দ্বারা গঠিত, যেখানে প্রতিটি নোডের মধ্যে ডেটা এবং পরবর্তী নোডের ঠিকানা থাকে। এটি ডেটাকে সংরক্ষণ করার জন্য একটি লিনিয়ার পদ্ধতি। লিংকড লিস্টের প্রধান সুবিধা হলো এর আকার পরিবর্তন করা সহজ।

গঠন:

struct Node {
    int data;                // নোডের ডেটা
    struct Node* next;      // পরবর্তী নোডের পয়েন্টার
};

উদাহরণ: লিংকড লিস্ট তৈরি ও প্রদর্শন

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

// নোডের গঠন
struct Node {
    int data;
    struct Node* next;
};

// নতুন নোড তৈরি করা
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// লিংকড লিস্টে ডেটা যোগ করা
void insertNode(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    newNode->next = *head; // নতুন নোডের পরবর্তী নোড হবে পুরনো হেড
    *head = newNode; // হেড আপডেট করা
}

// লিংকড লিস্ট প্রদর্শন করা
void displayList(struct Node* node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

int main() {
    struct Node* head = NULL; // লিংকড লিস্টের হেড
    insertNode(&head, 1);
    insertNode(&head, 2);
    insertNode(&head, 3);
    displayList(head); // লিংকড লিস্ট প্রদর্শন
    return 0;
}

আউটপুট:

3 -> 2 -> 1 -> NULL

২. স্ট্যাক (Stack)

স্ট্যাক হলো একটি লাস্ট ইন ফার্স্ট আউট (LIFO) ডেটা স্ট্রাকচার, যার অর্থ হলো যে ডেটা সর্বশেষে স্ট্যাকে যুক্ত হয়, সেটিই প্রথমে সরানো হয়। এটি সাধারণত মেমোরি ব্যবস্থাপনা, ফাংশন কল ট্রেস, এবং এক্সপ্রেশন মূল্যায়ন করতে ব্যবহৃত হয়।

গঠন:

#define MAX 100

struct Stack {
    int items[MAX];
    int top;
};

উদাহরণ: স্ট্যাক তৈরি ও ব্যবহার

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

#define MAX 100

struct Stack {
    int items[MAX];
    int top;
};

// স্ট্যাক ইনিশিয়ালাইজ
void initStack(struct Stack* s) {
    s->top = -1;
}

// স্ট্যাকে ডেটা যোগ করা
void push(struct Stack* s, int data) {
    if (s->top == MAX - 1) {
        printf("Stack overflow!\n");
    } else {
        s->items[++s->top] = data;
    }
}

// স্ট্যাক থেকে ডেটা সরানো
int pop(struct Stack* s) {
    if (s->top == -1) {
        printf("Stack underflow!\n");
        return -1;
    } else {
        return s->items[s->top--];
    }
}

// স্ট্যাকের শীর্ষ মান দেখানো
int peek(struct Stack* s) {
    if (s->top != -1) {
        return s->items[s->top];
    }
    return -1;
}

int main() {
    struct Stack s;
    initStack(&s);
    push(&s, 10);
    push(&s, 20);
    push(&s, 30);
    printf("Top item: %d\n", peek(&s)); // শীর্ষ মান দেখানো
    printf("Popped item: %d\n", pop(&s)); // স্ট্যাক থেকে সরানো
    printf("Top item after pop: %d\n", peek(&s));
    return 0;
}

আউটপুট:

Top item: 30
Popped item: 30
Top item after pop: 20

৩. কিউ (Queue)

কিউ হলো একটি ফার্স্ট ইন ফার্স্ট আউট (FIFO) ডেটা স্ট্রাকচার, যার অর্থ হলো যে ডেটা প্রথমে যুক্ত হয়, সেটিই প্রথমে সরানো হয়। এটি সাধারণত প্রক্রিয়া সময়সূচী, ডেটা স্ট্রিম প্রক্রিয়াকরণ, এবং অন্যান্য অ্যাসিনক্রোনাস কার্যক্রমে ব্যবহৃত হয়।

গঠন:

#define MAX 100

struct Queue {
    int items[MAX];
    int front, rear;
};

উদাহরণ: কিউ তৈরি ও ব্যবহার

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

#define MAX 100

struct Queue {
    int items[MAX];
    int front, rear;
};

// কিউ ইনিশিয়ালাইজ
void initQueue(struct Queue* q) {
    q->front = -1;
    q->rear = -1;
}

// কিউতে ডেটা যোগ করা
void enqueue(struct Queue* q, int data) {
    if (q->rear == MAX - 1) {
        printf("Queue overflow!\n");
    } else {
        if (q->front == -1) {
            q->front = 0;
        }
        q->items[++q->rear] = data;
    }
}

// কিউ থেকে ডেটা সরানো
int dequeue(struct Queue* q) {
    if (q->front == -1) {
        printf("Queue underflow!\n");
        return -1;
    } else {
        int data = q->items[q->front++];
        if (q->front > q->rear) {
            q->front = q->rear = -1; // কিউ খালি হলে
        }
        return data;
    }
}

// কিউয়ের শীর্ষ মান দেখানো
int peek(struct Queue* q) {
    if (q->front != -1) {
        return q->items[q->front];
    }
    return -1;
}

int main() {
    struct Queue q;
    initQueue(&q);
    enqueue(&q, 10);
    enqueue(&q, 20);
    enqueue(&q, 30);
    printf("Front item: %d\n", peek(&q)); // শীর্ষ মান দেখানো
    printf("Dequeued item: %d\n", dequeue(&q)); // কিউ থেকে সরানো
    printf("Front item after dequeue: %d\n", peek(&q));
    return 0;
}

আউটপুট:

Front item: 10
Dequeued item: 10
Front item after dequeue: 20

৪. ট্রি (Tree)

ট্রি হলো একটি হায়ারার্কিকাল ডেটা স্ট্রাকচার, যেখানে প্রতিটি নোডে ডেটা থাকে এবং একটি বা একাধিক সন্তানের নোড থাকতে পারে। ট্রি ডেটা স্ট্রাকচার সাধারণত বিভিন্ন তথ্য সংগঠিত করার জন্য ব্যবহৃত হয়।

গঠন:

struct Node {
    int data;
    struct Node* left;  // বাম সন্তান
    struct Node* right; // ডান সন্তান
};

উদাহরণ: একটি বাইনারি ট্রি তৈরি ও প্রদর্শন

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

// নোডের গঠন
struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

// নতুন নোড তৈরি করা
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->left = newNode->right = NULL;
    return newNode;
}

// ইনঅর্ডার ট্রাভার্সাল
void inorderTraversal(struct Node* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->data);
        inorderTraversal(root->right);
    }
}

int main() {
    struct Node* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);

    printf("Inorder Traversal: ");
    inorderTraversal(root); // ইনঅর্ডার ট্রাভার্সাল
    printf("\n");

    return 0;
}

আউটপুট:

Inorder Traversal: 4 2 5 1 3 
Content added By
Promotion

Are you sure to start over?

Loading...