جافا: احصل على ملكية فريدة من نوعها لكائن (مثل HASHCODE، ولكن دليل على الاصطدام)

StackOverflow https://stackoverflow.com/questions/1843565

  •  12-09-2019
  •  | 
  •  

سؤال

لدي مهمة ضرورية لتوليد قيمة فريدة لكل كائن في مجموعة. سيكون استخدام HASHCODE مثاليا، إذا لم يتم السماح بالاصطدامات في عقد Hashcode.

فكرة واحدة: سجل كل كائن Hashcode في Multiset. ثم، استخدم Hashcodes كمعرف فريد، ولكن إذا كان هذا hashcode في مجموعة أكثر من مرة، استخدم قيمة مختلفة ليست أيضا في المجموعة. ولكن هذا يشعر ضخمة وحرج.

أفكار أفضل؟

إليك ما لدي بالفعل:

public static <V> void toGraphViz(final Graph<V, DefaultWeightedEdge> g, String filename) {

    // to avoid hashcode collisions
    final Set<Integer> hashcodes = new HashSet<Integer>(g.vertexSet().size());

    DOTExporter<V, DefaultWeightedEdge> dot = new DOTExporter<V, DefaultWeightedEdge>(new VertexNameProvider<V> () {

    // vertex name must be unqiue
    @Override
    public String getVertexName(V arg0) {
        int hash = arg0.hashCode();
        while (hashcodes.contains((hash))) {
            hash += 1;
        }
        return "" + hash;
    }
}

تعديل: أعتقد أن هذا لم يكن واضحا في الأصل، ولكن رقم المعرف يحتاج إلى حد ما أن تكون وظيفة الكائن getVertexName(V) سوف تسمى عدة مرات، ويتوقع ذلك لنفس القيم V, ، سوف تحصل على نفس النتائج.

أيضا، نوع Vertex عام. لذلك لا يمكنني تقديم أي تعديلات على فئة محددة لإصلاح هذا.

هل كانت مفيدة؟

المحلول

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

إذا كانت فريدة من نوعها عبر العديد من عمليات الإعدام (وربما العديد من الحالات المتزامنة)، فربما يمكنك فقط استخدام قاعدة بيانات تقوم بإنشاء معرفات سجل Unqiue.

تحرير استجابة للتوضيح

قطعة فاتني من قبل كان لا يمكننا تعديل الفصل الذي نريد أن نولد "التجزئة" الفريدة.

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

public class Hasher {

    public  <V> void toGraphViz(final Graph<V, DefaultWeightedEdge> g, String filename) {
         final Map<V, Integer> hashcodes = new HashMap< V, Integer>();
         final int latestHashHolder[] = { 0 }; // array to allow access from inner class

         DOTExporter<V, DefaultWeightedEdge> dot 
                 = new DOTExporter<V, DefaultWeightedEdge>(new VertexNameProvider<V> ()) {

         // vertex name must be unqiue
            @Override
            public synchronized String getVertexName(V vertex) {
                int hashcode;
                if ( hashcodes.containsKey(vertex)){
                    hashcode = hashcodes.get(vertex);
                } else {                
                    hashcode = latestHashHolder[0];
                    latestHashHolder[0]++;
                    hashcodes.put(vertex, (Integer)latestHashHolder[0]);
                }
                return "Vertex-" + hashcode;
            }
        };
    }
}

نصائح أخرى

يمكنك التفكير في استخدام uuid., ، اعتمادا على ما تحاول إنجازه ...

للعثور على قيمة فريدة لكائن، يجب أن تعرف مجموعة من الخصائص التي تجعل الكائن فريدا.

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

على سبيل المثال، "(x، y، z، rgb)"

ما لم أسيء فهم السؤال، ما لم أسيء فهم السؤال، فلن أوصي بالتوصية ب Hashcode للكائن لهذا الغرض.

لماذا لا تستخدم فقط رقم تسلسلي؟

static private int serial=0;
static public synchronized nextSerialNumber() { return ++serial; }

أو مزيج / هجين، يقول طويلا ((Hash << 32) | getnextserial ()).

لمعالجة توضيح تحرير

عند إنشاء الكائن، قم بتخصيص الرقم التسلسلي إلى متغير عضو خاص وإرجاعه للحصول على Hashcode (). يجب عليك بعد ذلك تجاوز تساوي مكالمة إلى Super.Aqualeals () (نظرا لأن الرقم التسلسلي الذي تم إنشاؤه يتوافق مع التنفيذ الافتراضي () المستقيم ()) لأن رؤية التجزئة Hashcode () دون تجاوز المساواة () Will Red-Flag الرمز إلى الأدوات (وغيرها من المبرمجين).

public class Vertex
{
private final int                   serial;                                 // instance serial number

public Vertex() {
    serial=nextSerialNumber();
    ...
    }

public int hashCode() {
    return serial;
    }

public boolean equals(Object obj) {
    return super.equals(obj);                                               // serial number hash-code consistent with default equals    
    }

...        

static private int nextSerial=0;
static public synchronized nextSerialNumber() { return nextSerial++; }
}

أعتقد أنك أسيء فهم hashcode. بناء على العقد يجب أن يكون HASCODE هو نفسه عندما يساوي (..) صحيح والعكس صحيح. لذلك في حالتك، يجب أن يكون لدى Vertex مع نفس الخصائص نفسها نفسها، وإلا يجب إصلاح طريقة حساب Hascode المكتوبة بنفسك. بقدر ما فهمت سؤالك، فإن قمة الرأس لنفسها فريدة من نوعها، لذلك يجب ألا تواجه مشكلة، أليس كذلك؟

ربما لا أفهم ما تفعله، ولكن فكر في إنشاء مرجع لكل كائن. نظرا لأن المرجع يحتوي على عنوان الكائن سيكون فريدا لكل كائن.

ليس هذا صعبا، هل هو؟ ما عليك سوى استخدام خوارزمية التجزئة المختلفة، إذا كان الجهاز في جافا لا يضمن أي تصادم. أرسل الكائن إلى خوارزمية التجزئة، على سبيل المثال SHA-256، واستخدم ذلك كمفتاح. إذا كنت بحاجة إلى الاحتفاظ بنسخ مختلفة من نفس الكائن بالضبط، مع قيم التجزئة المختلفة، استخدم بذرة عند تنفيذ التجزئة، وتخزين هذا يتعلق بالكائن مع التجزئة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top