Common Data Structure Merging Techniques in Java

1. Merge and Deduplicate String Array Elements

Given a string array with duplicate elements, split (if needed), deduplicate, and merge. For example:
String[] input = {"array", "merge", "thread", "merge"};
Result: [array, merge, thread]

/**
 * Merge and deduplicate a string array (handles split if elements have commas).
 * @param input the source array
 * @return deduplicated list of strings
 */
private static List<String> mergeAndDeduplicate(String[] input) {
    return Arrays.stream(input)
        .map(str -> str.split(","))
        .flatMap(Arrays::stream)
        .distinct()
        .collect(Collectors.toList());
}

2. Merge Two Primitive Arrays (Int Arrays Example)

Method 1: Stream-based Merging with Deduplication

Merge two int arrays, sort, deduplicate, and return a new array.

private static int[] mergeAndDeduplicateArrays(int[] source, int[] target) {
    if (source.length == 0 && target.length == 0) return new int[0];
    if (source.length == 0) return target;
    if (target.length == 0) return source;
    
    return IntStream.concat(
            Arrays.stream(source).sorted(), 
            Arrays.stream(target).sorted()
        )
        .distinct()
        .toArray();
}

Method 2: Two-Pointer Technique (In-Place for One Array)

Merge two sorted arrays (in-place into the first array, assuming it has enough space).

/**
 * Merge two sorted arrays (nums1 has space for nums2).
 * @param nums1 first array (with size m + n)
 * @param m valid length of nums1
 * @param nums2 second array
 * @param n valid length of nums2
 */
public static void mergeSortedArrays(int[] nums1, int m, int[] nums2, int n) {
    int i = m - 1, j = n - 1;
    int index = m + n - 1; // End of merged array
    
    while (i >= 0 || j >= 0) {
        if (i >= 0 && j >= 0) {
            nums1[index--] = (nums1[i] >= nums2[j]) ? nums1[i--] : nums2[j--];
        } else if (i >= 0) {
            nums1[index--] = nums1[i--];
        } else {
            nums1[index--] = nums2[j--];
        }
    }
}

3. Merge Two Ordered Collections

import org.apache.commons.collections4.CollectionUtils;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public static List<Integer> mergeOrderedLists(List<Integer> listA, List<Integer> listB) {
    if (CollectionUtils.isEmpty(listA) && CollectionUtils.isEmpty(listB)) {
        return Collections.emptyList();
    }
    if (CollectionUtils.isEmpty(listA)) return listB;
    if (CollectionUtils.isEmpty(listB)) return listA;
    
    return Stream.of(listA, listB)
        .flatMap(Collection::stream)
        .distinct()
        .sorted()
        .collect(Collectors.toList());
}

4. Merge Two Binary Trees (Recursive)

class TreeNode {
    int val;
    TreeNode left, right;
    TreeNode(int val) { this.val = val; }
}

public static TreeNode mergeBinaryTrees(TreeNode treeA, TreeNode treeB) {
    if (treeA == null && treeB == null) return null;
    if (treeA == null) return treeB;
    if (treeB == null) return treeA;
    
    TreeNode merged = new TreeNode(treeA.val + treeB.val);
    merged.left = mergeBinaryTrees(treeA.left, treeB.left);
    merged.right = mergeBinaryTrees(treeA.right, treeB.right);
    return merged;
}

5. Merge Two Sorted Linked Lists (Recursive)

class ListNode {
    int val;
    ListNode next;
    ListNode(int val) { this.val = val; }
}

public static ListNode mergeSortedLists(ListNode listA, ListNode listB) {
    if (listA == null) return listB;
    if (listB == null) return listA;
    
    if (listA.val <= listB.val) {
        listA.next = mergeSortedLists(listA.next, listB);
        return listA;
    } else {
        listB.next = mergeSortedLists(listA, listB.next);
        return listB;
    }
}

6. Merge Two Maps (Java 8 merge())

import org.apache.commons.collections4.MapUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public static Map<String, Integer> mergeMaps(Map<String, Integer> mapA, Map<String, Integer> mapB) {
    if (MapUtils.isEmpty(mapA) && MapUtils.isEmpty(mapB)) {
        return Collections.emptyMap();
    }
    if (MapUtils.isEmpty(mapA)) return mapB;
    if (MapUtils.isEmpty(mapB)) return mapA;
    
    Map<String, Integer> result = new HashMap<>(mapA.size() > mapB.size() ? mapA : mapB);
    (mapA.size() > mapB.size() ? mapB : mapA).forEach(
        (k, v) -> result.merge(k, v, Integer::sum)
    );
    return result;
}

7. Convert Sorted Array to Binary Search Tree (BST)

class BSTNode {
    int val;
    BSTNode left, right;
    BSTNode(int val) { this.val = val; }
}

public BSTNode sortedArrayToBST(int[] nums) {
    return buildBST(nums, 0, nums.length - 1);
}

private BSTNode buildBST(int[] nums, int left, int right) {
    if (left > right) return null;
    int mid = left + (right - left) / 2; // Avoid overflow
    BSTNode root = new BSTNode(nums[mid]);
    root.left = buildBST(nums, left, mid - 1);
    root.right = buildBST(nums, mid + 1, right);
    return root;
}

8. Convert Sorted Linked List to BST

public BSTNode sortedListToBST(ListNode head) {
    if (head == null) return null;
    return buildBSTFromList(head, null);
}

private BSTNode buildBSTFromList(ListNode left, ListNode right) {
    if (left == right) return null;
    ListNode mid = findMiddle(left, right);
    BSTNode root = new BSTNode(mid.val);
    root.left = buildBSTFromList(left, mid);
    root.right = buildBSTFromList(mid.next, right);
    return root;
}

private ListNode findMiddle(ListNode left, ListNode right) {
    ListNode fast = left, slow = left;
    while (fast != right && fast.next != right) {
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

Dubbo Framework: Custom Data Structure Mergers

Dubbo’s Merger SPI allows merging results from multiple service invocations. Here’s how to implement custom mergers:

Merger Interface (SPI)

package com.example.dubbo.merger;

import com.alibaba.dubbo.common.extension.SPI;

@SPI
public interface Merger<T> {
    T merge(T... items);
}

Array Mergers (Example: Short Array)

package com.example.dubbo.merger.impl;

import com.example.dubbo.merger.Merger;

public class ShortArrayMerger implements Merger<short[]> {
    @Override
    public short[] merge(short[]... arrays) {
        int totalLength = 0;
        for (short[] arr : arrays) {
            totalLength += arr.length;
        }
        short[] result = new short[totalLength];
        int index = 0;
        for (short[] arr : arrays) {
            for (short element : arr) {
                result[index++] = element;
            }
        }
        return result;
    }
}

Colletcion Mergers (Example: Set)

package com.example.dubbo.merger.impl;

import com.example.dubbo.merger.Merger;
import java.util.HashSet;
import java.util.Set;

public class SetMerger implements Merger<Set<?>> {
    @Override
    public Set<Object> merge(Set<?>... sets) {
        Set<Object> merged = new HashSet<>();
        for (Set<?> set : sets) {
            if (set != null) {
                merged.addAll(set);
            }
        }
        return merged;
    }
}

Map Merger

package com.example.dubbo.merger.impl;

import com.example.dubbo.merger.Merger;
import java.util.HashMap;
import java.util.Map;

public class MapMerger implements Merger<Map<?, ?>> {
    @Override
    public Map<?, ?> merge(Map<?, ?>... maps) {
        if (maps.length == 0) return null;
        Map<Object, Object> result = new HashMap<>();
        for (Map<?, ?> map : maps) {
            if (map != null) {
                result.putAll(map);
            }
        }
        return result;
    }
}

These merger implementations handle different data types (arrays, sets, lists, maps) by concatenating or aggregating elements. The MergerFactory (not shown) caches and loads these mergers for efficient lookup.

Tags: java Data Structures merging Stream API Recursion

Posted on Mon, 02 Nov 2026 16:22:59 +0000 by daveoliveruk