آموزش کامل پیاده‌سازی Set در ساختمان داده

آموزش کامل پیاده‌سازی Set در ساختمان داده

تعریف set

در برنامه نویسی set نوعی پیاده‌سازی در ساختار داده است و set عناصر تکراری رو نگهداری نمیکنه

عنصر ها رو طبق ترتیبی که اضافه شدن نگهداری نمیکنه و بر خلاف لیست که با افزودن یک عنصر، عنصر بعد به طور خودکار تو خونه ی شماره ی بعدی آرایه قرار میگیره، در set با افزودن عنصر جدید، یک index تصادفی براش ایجاد میشه و به صورت تصادفی در خونه های موجود قرار می گیره.

نحوه ی قرار گرفتن عناصر اضافه شده در set
نحوه ی قرار گرفتن عناصر اضافه شده در set

در واقع set مشابه مجموعه ها در ریاضیاته یعنی یک مجموعه از عناصر که داخلش عنصر تکراری وجود نداشته باشه.

به set هایی که با هش کد (hashcode) پیاده می کنیم، HashSet میگیم، میتونیم HashSet رو مستقیم با هش کد یا از طریق یک رابطه ی aggregation با HashMap پیاده کنیم.

در این مطلب به پیاده‌سازی set از طریق رابطه ی aggregation با HashMap می پردازیم.

افزودن عنصر به set

برای اضافه کردن یک عنصر به set از تابعی به اسم add یا insert استفاده می کنیم؛ پیچیدگی زمان برای اضافه کردن یک عنصر به set برابر با O(1) است.

function add(E e): boolean{
  
  if !map.contains(e) 
    return false
  
  map.put(e, null)
  size++

  return true
}
        

بررسی وجود عنصر در set

برای بررسی یک عنصر در set از تابعی به نام contains استفاده می کنیم؛ در set پیچیدگی زمان برای جستجو O(1) است.

function contains(e: E): boolean{
  return map.containsKey(e)
}
        

حذف عنصر از set

برای حذف یک عنصر در set از تابعی به نام remove یا delete استفاده می کنیم؛‌ پیچیدگی زمان در set برای حذف یک عنصر O(1) است.

function remove(e: E): boolean{
  if !contains(e)
    return false

  map.remove(e)

  return true
}
        

تبدیل set به آرایه برای جستجوی خطی بین عناصر

میتونیم با استفاده از تابعی به نام toArray عناصر رو به صورت آرایه برگردونیم تا بتونیم به جستجوی خطی بین عناصر بپردازیم، پیچیدگی زمان برای این کار O(n) است.

function toArray(): Object[] {

  size := map.getSize()

  elements := new Object[size]

  entries := map.toArray()

  for 0<= i < entries.length
      elements[i] = entries[i]

  return elements
}
        

پیاده‌سازی set در زبان های برنامه نویسی

میخوایم یک HashSet رو با رابطه ی aggregation با HashMap در زبان های برنامه نویسی جاوا، کاتلین، جاوااسکریپت و پایتون پیاده کنیم.

در زیر نمودار uml پیاده‌سازی set آورده شده است.

نمودار uml پیاده‌سازی set در برنامه نویسی
نمودار uml پیاده‌سازی set در برنامه نویسی

برای راحتی یک دسترسی سریع به پیاده‌سازی ها با زبان های مختلف رو در زیر قرار دادیم.

پیاده‌سازی set با جاوا

میخوایم یک set رو به صورت جنریک با جاوا پیاده کنیم.

public class MyHashSet<E> {

    private final MyHashMap<E, Object> map = new MyHashMap<>();

    public boolean add(E e){

        if (map.containsKey(e)) return false;

        map.put(e, null);

        return true;
    }

    public boolean contains(E e){
        return map.containsKey(e);
    }

    public boolean remove(E e){

        if (!contains(e)) return false;

        map.remove(e);

        return true;
    }

    public int getSize() {
        return map.getSize();
    }

    public boolean isEmpty(){
       return map.isEmpty();
    }

    public Object[] toArray(){

        int size = map.getSize();
        Object[] elements = new Object[size];

        MyHashMap.Entry<E, Object>[] entries = map.toArray();

        for (int i=0; i<entries.length; i++){
            elements[i] = entries[i].getKey();
        }

        return elements;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder("[");

        Object[] array = toArray();

       for (int i=0; i<array.length; i++){
           sb.append(array[i]);
           if (i < array.length - 1){
               sb.append(", ");

           }
       }

       sb.append("]");

       return sb.toString();
    }
}
        

پیاده‌سازی set با کاتلین

در پایین میخوایم یک set رو به صورت جنریک در کاتلین پیاده کنیم.

class MyHashSet<E> {
    private val map: MyHashMap<E?, Any?> = MyHashMap()

    val size: Int
        get() = map.size

    val isEmpty: Boolean
        get() = map.isEmpty

    fun add(e: E?): Boolean {
        if (map.containsKey(e)) return false

        map.put(e, null)

        return true
    }

    fun contains(e: E?): Boolean {
        return map.containsKey(e)
    }

    fun remove(e: E?): Boolean {
        if (!contains(e)) return false

        map.remove(e)

        return true
    }

    fun toArray(): Array<Any?> {
        val size: Int = map.size
        val elements = arrayOfNulls<Any>(size)

        val entries: Array<MyHashMap.Entry<E?, Any?>?> = map.toArray()

        for (i in entries.indices) {
            elements[i] = entries[i]?.key
        }

        return elements
    }

    override fun toString(): String {
        val sb = StringBuilder("[")

        val array = toArray()

        for (i in array.indices) {
            sb.append(array[i])
            if (i < array.size - 1) {
                sb.append(", ")
            }
        }

        sb.append("]")

        return sb.toString()
    }
}
        

پیاده‌سازی set با جاوااسکریپت

زبان جاوااسکریپت یک زبان type-free است یعنی نوع متغیر هنگام مقداردهیش مشخص میشه، در زیر میخوایم یک set رو با جاوااسکریپت پیاده کنیم.

class MyHashSet {
    constructor() {
        this.map = new MyHashMap();
    }

    add(e) {
        if (this.map.containsKey(e)) return false;

        this.map.put(e, null);
        return true;
    }

    contains(e) {
        return this.map.containsKey(e);
    }

    remove(e) {
        if (!this.contains(e)) return false;

        this.map.remove(e);
        return true;
    }

    getSize() {
        return this.map.getSize();
    }

    isEmpty() {
        return this.map.isEmpty();
    }

    toArray() {
        const size = this.map.getSize();
        const elements = new Array(size);

        const entries = this.map.toArray();

        for (let i = 0; i < entries.length; i++) {
            elements[i] = entries[i].getKey();
        }

        return elements;
    }

    toString() {
        let sb = "[";
        const array = this.toArray();

        for (let i = 0; i < array.length; i++) {
            sb += array[i];
            if (i < array.length - 1) {
                sb += ", ";
            }
        }

        sb += "]";
        return sb;
    }
}
        

پیاده‌سازی set با پایتون

زبان پایتون یک زبان type-free است یعنی نوع متغیر هنگام مقداردهی مشخص میشه، در پایین میخوایم یک set رو در پایتون پیاده کنیم.

class MyHashSet:

    def __init__(self):
        self.map = MyHashMap()

    def add(self, e):
        if self.map.contains_key(e): 
            return False

        self.map.put(e, None)
        return True

    def contains(self, e):
        return self.map.contains_key(e)

    def remove(self, e):
        if not self.contains(e): 
            return False

        self.map.remove(e)
        return True

    def get_size(self):
        return self.map._size

    def is_empty(self):
        return self.map.is_empty()

    def to_array(self):
        size = self.map._size
        elements = [None] * size

        entries = self.map.to_array()

        for i in range(len(entries)):
            elements[i] = entries[i].get_key()

        return elements

    def __str__(self):
        sb = "["
        array = self.toArray()

        for i in range(len(array)):
            sb += str(array[i])
            if i < len(array) - 1:
                sb += ", "

        sb += "]"
        return sb
        

استفاده از set در زبان های برنامه نویسی

در این قسمت میخوایم با استفاده از set که بالا پیاده کردیم، اسم چند شهر رو ذخیره کنیم و (اسم یک شهر رو دوبار بنویسیم) و سپس دو شهر رو حذف کنیم و در نهایت شهر های داخل set رو نمایش بدیم.

MyHashSet<String> cities = new MyHashSet<>();

    cities.add("Tehran");
    cities.add("Arak");
    cities.add("Qom");
    cities.add("Hamadan");
    cities.add("Mashhad");
    cities.add("Tehran");

    cities.remove("Hamadan");
    cities.remove("Arak");

    System.out.println(cities);
        
val cities: MyHashSet<String> = MyHashSet()

    cities.add("Tehran")
    cities.add("Arak")
    cities.add("Qom")
    cities.add("Hamadan")
    cities.add("Mashhad")
    cities.add("Tehran")

    cities.remove("Hamadan")
    cities.remove("Arak")

    println(cities)
        
let cities = new MyHashSet();

cities.add("Tehran");
cities.add("Arak");
cities.add("Qom");
cities.add("Hamadan");
cities.add("Mashhad");
cities.add("Tehran");

cities.remove("Hamadan");
cities.remove("Arak");

console.log(cities.toString());
        
cities = MyHashSet()

cities.add("Tehran")
cities.add("Arak")
cities.add("Qom")
cities.add("Hamadan")
cities.add("Mashhad")
cities.add("Tehran")

cities.remove("Hamadan")
cities.remove("Arak")

print(cities)
        

خلاصه

  • از set در برنامه نویسی برای نگهداری عناصر غیر تکراری استفاده می کنیم.
  • اگه بخوایم set رو از طریق هش کد (hashcode) پیاده کنیم بهش HashSet میگیم.
  • میتونیم set رو مستقیم با هش کد یا از طریق رابطه ی aggregation با HashMap پیاده کنیم.
  • پیچیدگی زمان برای اضافه، حذف و جستجوی عنصر در set برابر با O(1) است.

بازخورد و دیدگاه‌ ها

اولین نفری باشید که در این صفحه نظر می‌دهید

notifications برای اطلاع از جدیدترین مطالب و پست های مرتبط، عضو کانال تلگرام ما بشید.

arrow_drop_up
کپی شد!