Does two lines of copied code constitute plagiarism?

It appears strongly likely that you did plagiarise, and if this is the case you'd be better to proceed by recognising your mistake than continuing to argue.

Looking at your code, there is a great deal that appears to have been taken from the HashMap.java file. I strongly suspect that you began with this code and then modified it to produce your code, or closely followed it as a template when writing your own. The highlighted code sections have picked up some of this, but other sections closely resemble the other file too, although with slightly altered comments and ordering.

If this is the case, then the code you have shown us is not your own original work but actually a plagiarised version of HashMap.java. Leaving in the two lines which are unconnected is a smoking gun of the link that is likely to be conclusive to the panel. Your point that they are unnecessary will actually count against you because you will be unable to explain why they are there at all. And whether this was your intent or not, it is likely that the panel (and your professor) will see your changed comments and ordering as an attempt to cover up your tracks and conceal your plagiarism from automated tools.

The panel is more likely to show leniency towards a student who appears to at least be contrite, and recognises that they've made a mistake, than a student who denies wrong-doing in the face of apparently very strong evidence.


The title of your question "does two lines of copied code constitute plagiarism", isn't exactly accurate, in my opinion.

I think that you will have a very hard time arguing that this isn't/wasn't plagiarism. The similarities between your code and HashMap.java don't end at the two lines or at a single "common algorithm".

1) You picked the exact same default capacity and load factor:

 /** Has to be a power of 2 */
 private static final int DEFAULT_CAPACITY = 16;

 /** The load factor */
 private static final float DEFAULT_LOAD_FACTOR = 0.75f;

versus

 // The default initial capacity - MUST be a power of two.
 static final int DEFAULT_INITIAL_CAPACITY = 16;

 // The load factor used when none specified in constructor.
 static final float DEFAULT_LOAD_FACTOR = 0.75f;

In fact, the "Has to be a power of 2" comment already means you are caught red-handed, because, there is, in fact, no good reason to require that the capacity is a power of two in your code. The fact that the size is a power of two is only used for an optimization in the HashMap.java version of the code, and this optimization isn't used in your code. You are probably lucky the student conduct board doesn't know much about programming.

2) The two get methods are very similar:

public V get(K key) {
    if (key == null)
        return null;
    int hash = key.hashCode() % data.length;
    // System.out.printf("Getting %d %d %s\n", key.hashCode(), hash,
    // key.toString());
    for (MyEntry<K, V> e = data[hash]; e != null; e = e.next) {
        if (e.hash == hash && (e.getKey() == key || key.equals(e.getKey())))
            return e.getValue();
    }

    return null;
}

versus

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    int hash = hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

It seems strange that you both picked the exact same, very specific way to do the key comparison (first comparing the hashes, then the pointers of the keys and then finally using key.equals).

3) ...as is the put-method:

public MyEntry<K, V> put(K key, V value) {
    int hash = key.hashCode();
    // System.out.printf("Adding %d %d %s\n", key.hashCode(), hash, key.toString());
    int i = hash % data.length;

    // Collisions
    for (MyEntry<K, V> e = data[i]; e != null; e = e.next) {
        if (e.hash == hash && (e.getKey() == key || key.equals(e.getKey()))) {
            MyEntry<K, V> old = e;
            e.setValue(value);
            return old;
        }
    }

    addEntry(hash, key, value, i);

    return null;
}

versus

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

4) ...as are the add and grow-methods:

void addEntry(int hash, K key, V value, int bucketIndex) {
    MyEntry<K, V> e = data[bucketIndex];
    data[bucketIndex] = new MyEntry<>(hash, key, value, e);
    keyList.add(key);

    if (size++ >= threshold)
        grow();
}

/**
 * Grows the array 2x current size
 */
private void grow() {
    int newSize = 2 * data.length;

    @SuppressWarnings("unchecked")

    MyEntry<K, V>[] newArr = new MyEntry[newSize];
    // Copy
    for (int i = 0; i < data.length; i++) {
        MyEntry<K, V> e = data[i];
        if (e != null) {
            data[i] = null;
            do {
                MyEntry<K, V> next = e.next;
                int j = e.hash % newSize;

                e.next = newArr[j];
                newArr[j] = e;
                e = next;
            } while (e != null);
        }
    }

    data = newArr;
    threshold = (int) (newSize * DEFAULT_LOAD_FACTOR);
}

versus

void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<>(hash, key, value, e);
    if (size++ >= threshold)
        resize(2 * table.length);
}

void transfer(Entry[] newTable) {
    Entry[] src = table;

    int newCapacity = newTable.length;
    for (int j = 0; j < src.length; j++) {
        Entry<K,V> e = src[j];
        if (e != null) {
            src[j] = null;
            do {
                Entry<K,V> next = e.next;
                int i = indexFor(e.hash, newCapacity);

                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            } while (e != null);
        }
    }
}

Of course, a HashTable is a fairly common data structure and there are only so many ways to implement a given algorithm. However, the two copied lines show that you did definitely use HashTable.java as a starting point for your own implementation, and the further similarities in the design, illogical comments and code structure would lead one to believe that you did take more than just a little "inspiration" from HashTable.java.

Note that both your and their put and get methods use a for-loop to iterate over a linked list, whereas the grow/transfer methods uses a while-loop to do the same. It seems strange that both pieces of code would make this same decision independently.

Our projects are pretty extensive since we aren't allowed to use java.util.* (like 1k+ lines for each project in 8 days), and I did not copy any other code. I'd say the actual data structure implementation is only meant to take about 1/5 our time spent per project.

It seems clear that you weren't allowed to use HashMap.java, and that, if you had wanted to use a hash table, you'd need to implement your own. By copying large parts of HashMap.java you've tried to circumvent this restriction. "It's only a small part of the project" doesn't take away the fact that you took code, that was not your own work, and tried to pass it off as your own (even though the expectation was that you'd write this part of the assignment yourself).

If the assignments were truly unrealistic given the time span allocated, it would have been better to turn in a failing solution. If many students turned in a failing solution, the professor might have considered the possibility that the assignment was too hard. If the plagiarism had gone unnoticed then the professor might have (incorrectly) concluded that the assignment was of appropriate difficulty, penalizing the students who (attempted) to complete the assignment fairly and according to the rules.

The penalties for plagiarism can vary greatly by institution. -100% on your assignment could be heavy handed, but at our institution the penalty could have been anywhere from 0% on the assignment, an automatic fail for the course in question to expulsion from your studies for 12 months. Plagiarism, at most institutions, is treated similarly to cheating on an exam and the punishments might be stringent. If the only punishment were getting 0% on the plagiarized assignment then there would be no harm in "trying" to plagiarize if you'd fail the assignment anyways without resorting to plagiarism.


Plagiarism is passing someone else's work as your own. From what I see, you have passed someone else's work as your own. In your defence, you provide a list of statements:

  • the plagiarised fragment of code is small
  • the plagiarised fragment of code is not necessary
  • the professor's assignments are hard
  • the professor is newly graduated
  • the Student Conduct Board knows little about programming

I can't see how any of them are relevant to the issue in question. The central question is: have you used someone else's work in your own without references. If you did, you plagiarised, and you're facing consequences. Learn the lesson and do not repeat the mistake again.