জাভাতে কীভাবে গাছের ডেটা-কাঠামো বাস্তবায়ন করবেন? [বন্ধ]


496

জাভাতে কোন গাছের প্রতিনিধিত্ব করার জন্য জাভা গ্রন্থাগারের কোনও মানক মান আছে?

বিশেষত আমাকে নিম্নলিখিতগুলি উপস্থাপন করতে হবে:

  • যে কোনও নোডের উপ-গাছে একটি নির্বিচার সংখ্যক শিশু থাকতে পারে
  • প্রতিটি নোড (মূলের পরে) এবং এর শিশুদের স্ট্রিংয়ের মান হবে
  • আমাকে একটি প্রদত্ত নোডের সমস্ত বাচ্চাদের (স্ট্রিংগুলির কয়েকটি ধরণের তালিকা বা অ্যারের) পাওয়া দরকার এবং এটির স্ট্রিংয়ের মান (অর্থাত্ একটি পদ্ধতি যা ইনপুট হিসাবে নোড নেবে এবং আউটপুট হিসাবে নোডের সমস্ত স্ট্রিংয়ের মান ফেরত দেবে)

এর জন্য কি কোনও উপলভ্য কাঠামো আছে বা আমার নিজের তৈরি করার দরকার আছে (যদি বাস্তবায়নের পরামর্শগুলি দুর্দান্ত হয়)।


3
আপনি যদি জাভা 8 ব্যবহার করছেন এবং আপনার নোডগুলি স্ট্রিম, ফিল্টারিং ইত্যাদির সাথে অতিক্রম করতে চান; তারপরে আপনি ডিউরিয়ান github.com/diffplug/durian
নেড

1
: আপনি এই এপিআই ব্যবহার করতে পারেন sourceforge.net/p/treeds4j
মোহাম্মদ Ennahdi এল Idrissi

উত্তর:


306

এখানে:

public class Tree<T> {
    private Node<T> root;

    public Tree(T rootData) {
        root = new Node<T>();
        root.data = rootData;
        root.children = new ArrayList<Node<T>>();
    }

    public static class Node<T> {
        private T data;
        private Node<T> parent;
        private List<Node<T>> children;
    }
}

এটি একটি মৌলিক গাছ কাঠামো যা Stringঅন্য কোনও বস্তুর জন্য বা ব্যবহার করা যেতে পারে । আপনার যা প্রয়োজন তা করতে সাধারণ গাছগুলি কার্যকর করা মোটামুটি সহজ।

আপনাকে যে সমস্ত সংযোজন করতে হবে তা হ'ল অ্যাড, সরানো, ট্র্যাভারসিং এবং কনস্ট্রাক্টর পদ্ধতি। এটি Nodeহল প্রাথমিক বিল্ডিং ব্লক Tree


304
কঠোরভাবে Treeক্লাসে কথা বলা প্রয়োজন হয় না, কারণ প্রত্যেকে Nodeনিজের মধ্যে গাছ হিসাবে দেখা যায়।
জোচিম সৌর

34
@ জোয়া, আমি মূলটি ধারণ করার মতো কাঠামো চাই like আপনি গাছের শ্রেণিতে এমন একটি পদ্ধতি যুক্ত করতে পারেন যা কোনও নোডের পরিবর্তে গাছে ফোন করার জন্য আরও বেশি অর্থবোধ করে।
jjnguy

24
@ জাস্টিন: উদাহরণস্বরূপ? এটি একটি সত্যই প্রশ্ন: আমি এমন একটি পদ্ধতিও ভাবতে পারি না যা পুরো গাছটিকে বোঝায় যা উপ-গাছে বোঝায় না।
জোচিম সউর

22
আমি @ জোয়ার সাথে একমত যে বৃক্ষ শ্রেণিটি প্রয়োজনীয় নয়। আমি পৃথক ট্রি ক্লাস না যোগ করে এবং নিয়মিত নোড ক্লাস ব্যবহার না করে কোডগুলিতে গাছের পুনরাবৃত্ত প্রকৃতি ছেড়ে যেতে পছন্দ করি। পরিবর্তে আমি একটি পরিবর্তনশীল 'গাছ' বা 'রুট' নাম রাখি যদি এটি পরিষ্কার হওয়া দরকার যে আপনি কোনও গাছের মূল নোডের সাথে কাজ করছেন।
jvdbogae

89
@ জোয়া চার বছরের বড় আমার সাথে সম্পূর্ণরূপে একমত। নিক্স গাছের ক্লাস।
jjnguy

122

তবুও অন্য গাছের কাঠামো:

public class TreeNode<T> implements Iterable<TreeNode<T>> {

    T data;
    TreeNode<T> parent;
    List<TreeNode<T>> children;

    public TreeNode(T data) {
        this.data = data;
        this.children = new LinkedList<TreeNode<T>>();
    }

    public TreeNode<T> addChild(T child) {
        TreeNode<T> childNode = new TreeNode<T>(child);
        childNode.parent = this;
        this.children.add(childNode);
        return childNode;
    }

    // other features ...

}

নমুনা ব্যবহার:

TreeNode<String> root = new TreeNode<String>("root");
{
    TreeNode<String> node0 = root.addChild("node0");
    TreeNode<String> node1 = root.addChild("node1");
    TreeNode<String> node2 = root.addChild("node2");
    {
        TreeNode<String> node20 = node2.addChild(null);
        TreeNode<String> node21 = node2.addChild("node21");
        {
            TreeNode<String> node210 = node20.addChild("node210");
        }
    }
}

বোনাস এর সাথে
সম্পূর্ণ সজ্জিত গাছ দেখুন:

  • পুনরুক্তিকারীর
  • অনুসন্ধান
  • জাভা / সি #

https://github.com/gt4dev/yet-another-tree-structure


2
সবেমাত্র আপনার গ্রন্থাগারটি অত্যন্ত দরকারী বলে মনে হয়েছে। ধন্যবাদ. তবে আমি জানতে চাই যে কীভাবে পিতামাতা এবং সন্তানের মধ্যে উল্লেখের সম্পর্কের ভিত্তিতে গাছের কাঠামোকে গতিশীলভাবে প্রয়োগ করা যায়। প্রদত্ত উদাহরণটি হ'ল আমার কাছে একজন সদস্য 1 অন্য সদস্য 2 স্পনসর এবং সদস্য 2 স্পনসর সদস্য 3 এবং তাই এবং তাই। ইতিমধ্যে টেবিলের রেকর্ডের সম্পর্ক রয়েছে তবে আমি নিশ্চিত না যে আমি আপনার লাইব্রেরিটি ব্যবহার করে এগুলিকে একটি গাছে পরিণত করতে পারি।
d4v1dv00

1
২০১ of সালের হিসাবে, লিঙ্কটিতে কোনও উত্স ফাইল বা ডাউনলোড নেই
শ্যারন বেন আশের

2
আমার দৃষ্টিতে, উপরের উচ্চতর রেট করা উত্তরের তিন বছর পরে এই উত্তরটি ক্লিনার। তবে আমি লিঙ্কডলিস্টটি এই.চাইল্ডেনের জন্য একটি অ্যারেলিস্টের সাথে প্রতিস্থাপন করব।
হোপকিং

1
আমি বাচ্চাদের জন্য একটি সেট ব্যবহার করব।
ডিপিএম

আমি ভুল হতে পারি তবে মনে হয় এই প্রয়োগের সাথে বৈধ ফলাফল পেতে hasNext()প্রতিটি কল করার আগে আপনাকে অবশ্যই কল করতে হবে next()। এটি Iteratorঅনুমানের অংশ নয় ।
রবার্ট লুইস

97

জেডিকেতে বাস্তবে বেশ ভাল গাছের কাঠামো প্রয়োগ করা হয়েছে।

কটাক্ষপাত আছে javax.swing.tree , TreeModel এবং TreeNode । এগুলি এর সাথে ব্যবহারের জন্য ডিজাইন করা হয়েছে JTreePanelতবে তারা প্রকৃতপক্ষে একটি দুর্দান্ত গাছের বাস্তবায়ন এবং সুইং ইন্টারফেসের সাহায্যে এটি ব্যবহার করা থেকে বিরত কিছু নেই।

নোট করুন যে জাভা 9 হিসাবে আপনি এই ক্লাসগুলি ব্যবহার না করার ইচ্ছা করতে পারেন কারণ তারা 'কমপ্যাক্ট প্রোফাইলে' উপস্থিত থাকবে না ।


5
হ্যাঁ, আমি এগুলিকে অতীতে ব্যবহার করেছি এবং তারা গাছ থেকে আপনার যা কিছু চাইবে তাই করবে। আমি কেবলমাত্র খারাপ দিক বিবেচনা করতে পারি তা হ'ল তাদের নিজ নিজ প্রয়োগকারী শ্রেণীর নামগুলির দৈর্ঘ্য: ডিফল্টট্রিমোডেল এবং ডিফল্টমুটেবলট্রি নোড। ভার্বোস, তবে এটি আমার অনুমানের মতো গুরুত্বপূর্ণ নয়।
চূড়ান্ত গাব্বলমেন্ট

4
এর সাথে মোকাবিলা করার ভাল উপায় হ'ল কয়েকটি মডেল () এবং নতুননোড () স্ট্যাটিক পদ্ধতি তৈরি করা এবং তারপরে স্থির সেগুলি আমদানি করা।
গ্যারেথ ডেভিস

140
আমি সুইং-সম্পর্কিত ফাংশনগুলিতে সুইং গ্রন্থাগারগুলি ব্যবহার করা এড়াতে চাই। এটি খারাপ কোডিং অনুশীলন । আপনি কখনই জানেন না যে সুইং কীভাবে তাদের গাছগুলি কার্যকর করে, তাদের নির্ভরতা কী এবং ভবিষ্যতে কীভাবে এটি পরিবর্তিত হতে পারে। সুইং কোনও ইউটিলিটি লাইব্রেরি নয় একটি ইউআই লাইব্রেরি।
jasop

44
আমি মনে করি খারাপ কোডিং অনুশীলনটি কিছুটা কঠোর।
গ্যারেথ ডেভিস

51
javax.swing.tree.TreeModel একটি সর্বজনীন ইন্টারফেস (ঠিক java.util.List এর মত) এবং এতে বেমানান পরিবর্তন হবে না। একটি অতিরিক্ত সুবিধা হ'ল আপনি যখন আপনার গাছ বিকাশের সময় সহজেই ডিবাগ / ভিজ্যুয়ালাইজ করতে পারেন could
lbalazscs

45

এই সম্পর্কে কি?

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

/**
  * @author ycoppel@google.com (Yohann Coppel)
  * 
  * @param <T>
  *          Object's type in the tree.
*/
public class Tree<T> {

  private T head;

  private ArrayList<Tree<T>> leafs = new ArrayList<Tree<T>>();

  private Tree<T> parent = null;

  private HashMap<T, Tree<T>> locate = new HashMap<T, Tree<T>>();

  public Tree(T head) {
    this.head = head;
    locate.put(head, this);
  }

  public void addLeaf(T root, T leaf) {
    if (locate.containsKey(root)) {
      locate.get(root).addLeaf(leaf);
    } else {
      addLeaf(root).addLeaf(leaf);
    }
  }

  public Tree<T> addLeaf(T leaf) {
    Tree<T> t = new Tree<T>(leaf);
    leafs.add(t);
    t.parent = this;
    t.locate = this.locate;
    locate.put(leaf, t);
    return t;
  }

  public Tree<T> setAsParent(T parentRoot) {
    Tree<T> t = new Tree<T>(parentRoot);
    t.leafs.add(this);
    this.parent = t;
    t.locate = this.locate;
    t.locate.put(head, this);
    t.locate.put(parentRoot, t);
    return t;
  }

  public T getHead() {
    return head;
  }

  public Tree<T> getTree(T element) {
    return locate.get(element);
  }

  public Tree<T> getParent() {
    return parent;
  }

  public Collection<T> getSuccessors(T root) {
    Collection<T> successors = new ArrayList<T>();
    Tree<T> tree = getTree(root);
    if (null != tree) {
      for (Tree<T> leaf : tree.leafs) {
        successors.add(leaf.head);
      }
    }
    return successors;
  }

  public Collection<Tree<T>> getSubTrees() {
    return leafs;
  }

  public static <T> Collection<T> getSuccessors(T of, Collection<Tree<T>> in) {
    for (Tree<T> tree : in) {
      if (tree.locate.containsKey(of)) {
        return tree.getSuccessors(of);
      }
    }
    return new ArrayList<T>();
  }

  @Override
  public String toString() {
    return printTree(0);
  }

  private static final int indent = 2;

  private String printTree(int increment) {
    String s = "";
    String inc = "";
    for (int i = 0; i < increment; ++i) {
      inc = inc + " ";
    }
    s = inc + head;
    for (Tree<T> child : leafs) {
      s += "\n" + child.printTree(increment + indent);
    }
    return s;
  }
}

5
এই শ্রেণীর অবজেক্টটি ব্যবহার করে কোনও গাছে ডিএফএস কীভাবে প্রয়োগ করা হবে?
লেবা-লেভ

3
এই শ্রেণিটি ব্যবহার করে কোনও পাতা অপসারণ কীভাবে কার্যকর করা হবে?
'32 এ গিদা

2
মাথার ক্ষেত্রটি কী জন্য ব্যবহার করা হবে?
Acour83

2
এই শ্রেণীর কিছু ডকুমেন্টেশন থাকলে এটি দুর্দান্ত হত। আমি কী পদ্ধতিগুলি পছন্দ setAsParentবা getHeadকরি তা আমি বেশ বুঝতে পারি না এবং এই সময়টি যখন আমি সত্যিই গাছের ডেটা কাঠামোয় কিছু সহায়তা পেতে পারি। এমনকি নথির মূল উত্স সম্পর্কে কোনও মন্তব্য নেই।
বিপর্যয়

23

আমি একটি ছোট লাইব্রেরি লিখেছি যা জেনেরিক গাছগুলি পরিচালনা করে। এটি সুইং স্টাফের চেয়ে অনেক বেশি হালকা ওজনের। আমার এটির জন্য একটি মাভেন প্রকল্পও রয়েছে


3
আমি এখন এটি ব্যবহার করছি, উজ্জ্বলতার সাথে কাজ করে। আমার নিজস্ব কাস্টমাইজেশনের জন্য উত্সটি উল্লেখযোগ্যভাবে পরিবর্তন করতে হয়েছিল তবে এটি একটি দুর্দান্ত সূচনা পয়েন্ট ছিল। ধন্যবাদ ভিভিন!
jasop

20
public class Tree {
    private List<Tree> leaves = new LinkedList<Tree>();
    private Tree parent = null;
    private String data;

    public Tree(String data, Tree parent) {
        this.data = data;
        this.parent = parent;
    }
}

স্পষ্টতই আপনি বাচ্চাদের যুক্ত / সরানোর জন্য ইউটিলিটি পদ্ধতি যুক্ত করতে পারেন।


1
এটি পরামর্শ দেয় যে গাছের পিতামাতা একটি গাছ। আমি বিশ্বাস করি আপনি একটি ট্রি নোড ক্লাস তৈরি করার চেষ্টা করছেন।
মধুর ভার্গব

16

আপনার গাছটি (ডোমেনের জন্য) কী তা নির্ধারণ করে শুরু করা উচিত, এটি প্রথমে ইন্টারফেসটি সংজ্ঞায়নের মাধ্যমে করা ভাল । সমস্ত গাছের কাঠামোগুলি পরিবর্তনযোগ্য নয়, নোডগুলি যুক্ত করতে এবং অপসারণ করতে সক্ষম হওয়া একটি alচ্ছিক বৈশিষ্ট্য হওয়া উচিত, তাই আমরা তার জন্য একটি অতিরিক্ত ইন্টারফেস তৈরি করি।

মানগুলি ধারণ করে এমন নোড অবজেক্ট তৈরি করার দরকার নেই , প্রকৃতপক্ষে আমি এটিকে বেশিরভাগ গাছ বাস্তবায়নের ক্ষেত্রে একটি প্রধান নকশার ত্রুটি এবং ওভারহেড হিসাবে দেখি। আপনি যদি সুইংয়ের দিকে লক্ষ্য করেন তবে TreeModelএটি নোড ক্লাসগুলি থেকে মুক্ত (কেবলমাত্র এটি DefaultTreeModelব্যবহার করে TreeNode), কারণ তাদের সত্যিকারের প্রয়োজন নেই।

public interface Tree <N extends Serializable> extends Serializable {
    List<N> getRoots ();
    N getParent (N node);
    List<N> getChildren (N node);
}

মিউটেবল গাছের কাঠামো (নোডগুলি যুক্ত করতে এবং মুছে ফেলার অনুমতি দেয়):

public interface MutableTree <N extends Serializable> extends Tree<N> {
    boolean add (N parent, N node);
    boolean remove (N node, boolean cascade);
}

এই ইন্টারফেসগুলি দেওয়া, যে কোডগুলি গাছ ব্যবহার করে তাদের কীভাবে গাছটি প্রয়োগ করা হয় সে সম্পর্কে খুব বেশি যত্ন নেওয়া প্রয়োজন না। এটি আপনাকে জেনেরিক প্রয়োগ এবং সেইসাথে বিশেষায়িত জিনিসগুলি ব্যবহার করতে সহায়তা করে যেখানে আপনি অন্য API এ ফাংশনগুলি অর্পণ করে গাছটি উপলব্ধি করতে পারেন।

উদাহরণ: ফাইল গাছ কাঠামো

public class FileTree implements Tree<File> {

    @Override
    public List<File> getRoots() {
        return Arrays.stream(File.listRoots()).collect(Collectors.toList());
    }

    @Override
    public File getParent(File node) {
        return node.getParentFile();
    }

    @Override
    public List<File> getChildren(File node) {
        if (node.isDirectory()) {
            File[] children = node.listFiles();
            if (children != null) {
                return Arrays.stream(children).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }
}

উদাহরণ: জেনেরিক ট্রি স্ট্রাকচার (পিতামাতার / সন্তানের সম্পর্কের উপর ভিত্তি করে):

public class MappedTreeStructure<N extends Serializable> implements MutableTree<N> {

    public static void main(String[] args) {

        MutableTree<String> tree = new MappedTreeStructure<>();
        tree.add("A", "B");
        tree.add("A", "C");
        tree.add("C", "D");
        tree.add("E", "A");
        System.out.println(tree);
    }

    private final Map<N, N> nodeParent = new HashMap<>();
    private final LinkedHashSet<N> nodeList = new LinkedHashSet<>();

    private void checkNotNull(N node, String parameterName) {
        if (node == null)
            throw new IllegalArgumentException(parameterName + " must not be null");
    }

    @Override
    public boolean add(N parent, N node) {
        checkNotNull(parent, "parent");
        checkNotNull(node, "node");

        // check for cycles
        N current = parent;
        do {
            if (node.equals(current)) {
                throw new IllegalArgumentException(" node must not be the same or an ancestor of the parent");
            }
        } while ((current = getParent(current)) != null);

        boolean added = nodeList.add(node);
        nodeList.add(parent);
        nodeParent.put(node, parent);
        return added;
    }

    @Override
    public boolean remove(N node, boolean cascade) {
        checkNotNull(node, "node");

        if (!nodeList.contains(node)) {
            return false;
        }
        if (cascade) {
            for (N child : getChildren(node)) {
                remove(child, true);
            }
        } else {
            for (N child : getChildren(node)) {
                nodeParent.remove(child);
            }
        }
        nodeList.remove(node);
        return true;
    }

    @Override
    public List<N> getRoots() {
        return getChildren(null);
    }

    @Override
    public N getParent(N node) {
        checkNotNull(node, "node");
        return nodeParent.get(node);
    }

    @Override
    public List<N> getChildren(N node) {
        List<N> children = new LinkedList<>();
        for (N n : nodeList) {
            N parent = nodeParent.get(n);
            if (node == null && parent == null) {
                children.add(n);
            } else if (node != null && parent != null && parent.equals(node)) {
                children.add(n);
            }
        }
        return children;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        dumpNodeStructure(builder, null, "- ");
        return builder.toString();
    }

    private void dumpNodeStructure(StringBuilder builder, N node, String prefix) {
        if (node != null) {
            builder.append(prefix);
            builder.append(node.toString());
            builder.append('\n');
            prefix = "  " + prefix;
        }
        for (N child : getChildren(node)) {
            dumpNodeStructure(builder, child, prefix);
        }
    }
}

1
আমি যখন বৃক্ষ.এডিডি ("এ", "বি") করি যখন আমি এই কাঠামোটি অনুসরণ করি তখন আমি একটি সমস্যার মুখোমুখি হয়েছি; ট্রি.এডিডি ("এ", "সি"); ট্রি.এডিডি ("সি", "ডি"); ট্রি.এডিডি ("ই", "এ"); E হ'ল A এর পিতামাতা আমরা কীভাবে এটি করা যায়?
saNiks

1
হাই সানিক্স, উপরের কোডটিতে একটি ত্রুটি ছিল যার ফলে শেষের সম্পর্কটি যুক্ত করা হয়নি। এটি এখনই স্থির হয়েছে, এবং আমি নন-নাল চেক এবং আরও গুরুত্বপূর্ণও যুক্ত করেছি: চক্রীয় চেক যা গাছের কাঠামো লঙ্ঘন করতে বাধা দেয় (একটি কোড বা তার পূর্বপুরুষদের মধ্যে একটি শিশু হিসাবে নিজেকে যুক্ত করে)। ইঙ্গিতটির জন্য ধন্যবাদ!
পিটার ওয়ালসার

1
আমি বাগটি ঠিক করেছি যদি কেউ সেই বাগের জন্য কোনও সমাধানের সন্ধান করে তবে আপনাকে যা করতে হবে তা দেখুন অ্যাড পদ্ধতিটি মিথ্যা প্রত্যাবর্তন করে এবং যদি এটি মিথ্যা হয় কেবল একটি অল্প অল্প নতুন লিঙ্কডহ্যাশসেট <এন> তৈরি করে এবং এতে গাছের নোডলিস্টটিকে ক্লোন করে দেয় তবে আপনি সাফ করতে পারবেন গাছটি, পূর্বের পদক্ষেপে যুক্ত না হওয়া প্যারেন্ট নোড যুক্ত করুন এবং তারপরে টেম্পনোডের সমস্ত অ্যাড যোগ করুন মূল গাছটিতে ... যদিও কাঠামোর জন্য ধন্যবাদ!
saNiks

2
আপনার ইন্টারফেস থেকে কেবল সেই অকেজো পাবলিক সংশোধকগুলি সরান ।
হামেদজ

1
আমি এর থেকে কীভাবে একটি জসন অ্যারে জেনারেট করতে পারি
পবন পান্ডে

12

কোনও উত্তর অতিরিক্ত-সরলকৃত তবে কার্যকরী কোডের উল্লেখ করে না, সুতরাং এটি এখানে:

public class TreeNodeArray<T> {
    public T value;
    public final  java.util.List<TreeNodeArray<T>> kids =  new java.util.ArrayList<TreeNodeArray<T>>();
}

10

আপনি জাভার যে কোনও এক্সএমএল এপিআইটি ডকুমেন্ট এবং নোড হিসাবে ব্যবহার করতে পারেন..যে এক্সএমএল স্ট্রিং সহ একটি গাছের কাঠামো


5
দুর্দান্ত আইডিয়া, আমরা নোডগুলি অনুসন্ধান করতে dom4j + jaxen xpath ব্যবহার করে মেমরি এক্সএমএল স্কিমা ব্যবহার করতে পারি।
বেন রোউমা জিড

8

যদি আপনি হোয়াইটবোর্ড কোডিং, একটি সাক্ষাত্কার বা এমনকি একটি গাছ ব্যবহারের পরিকল্পনা করছেন তবে এগুলির ভার্বোসটি কিছুটা বেশি।

এটি আরও বলা উচিত যে গাছটি সেখানে না থাকার কারণ হিসাবে বলুন, একটি Pair(যার বিষয়ে একইটি বলা যেতে পারে) এটি হ'ল কারণ এটি আপনার ক্লাসে আপনার ডেটাটি ব্যবহার করে ব্যবহার করা উচিত, এবং সহজ রূপায়ণটি দেখে মনে হচ্ছে:

/***
/* Within the class that's using a binary tree for any reason. You could 
/* generalize with generics IFF the parent class needs different value types.
 */
private class Node {
  public String value;
  public Node[] nodes; // Or an Iterable<Node> nodes;
}

এটি একটি বিস্ময়কর প্রস্থ গাছের জন্য সত্যই।

আপনি যদি বাইনারি গাছ চান তবে নামযুক্ত ক্ষেত্রগুলি সহ এটি প্রায়শই সহজ easier

private class Node { // Using package visibility is an option
  String value;
  Node left;
  Node right;
}

অথবা আপনি যদি একটি ট্রাই চেয়েছিলেন:

private class Node {
  String value;
  Map<char, Node> nodes;
}

এখন আপনি বলেছেন আপনি চান

সমস্ত বাচ্চাকে (স্ট্রিংগুলির কয়েকটি ধরণের তালিকা বা অ্যারে) পেতে সক্ষম হবেন একটি প্রদত্ত নোড উপস্থাপন করে একটি ইনপুট স্ট্রিং

এটা আপনার হোমওয়ার্ক মত শোনাচ্ছে।
তবে যেহেতু আমি যুক্তিসঙ্গতভাবে নিশ্চিত যে কোনও সময়সীমা এখন কেটে গেছে ...

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

public class kidsOfMatchTheseDays {
 static private class Node {
   String value;
   Node[] nodes;
 }

 // Pre-order; you didn't specify.
 static public List<String> list(Node node, String find) {
   return list(node, find, new ArrayList<String>(), false);
 }

 static private ArrayList<String> list(
     Node node,
     String find,
     ArrayList<String> list,
     boolean add) {
   if (node == null) {
     return list;
   }
   if (node.value.equals(find)) {
     add = true;
   }
   if (add) {
     list.add(node.value);
   }
   if (node.nodes != null) {
     for (Node child: node.nodes) {
       list(child, find, list, add);
     }
   }
   return list;
 }

 public static final void main(String... args) {
   // Usually never have to do setup like this, so excuse the style
   // And it could be cleaner by adding a constructor like:
   //     Node(String val, Node... children) {
   //         value = val;
   //         nodes = children;
   //     }
   Node tree = new Node();
   tree.value = "root";
   Node[] n = {new Node(), new Node()};
   tree.nodes = n;
   tree.nodes[0].value = "leftish";
   tree.nodes[1].value = "rightish-leafy";
   Node[] nn = {new Node()};
   tree.nodes[0].nodes = nn;
   tree.nodes[0].nodes[0].value = "off-leftish-leaf";
   // Enough setup
   System.out.println(Arrays.toString(list(tree, args[0]).toArray()));
 }
}

এটি আপনার মতো ব্যবহার করে:

$ java kidsOfMatchTheseDays leftish
[leftish, off-leftish-leaf]
$ java kidsOfMatchTheseDays root
[root, leftish, off-leftish-leaf, rightish-leafy]
$ java kidsOfMatchTheseDays rightish-leafy
[rightish-leafy]
$ java kidsOfMatchTheseDays a
[]

7

গ্যারেথের উত্তর হিসাবে একই লাইন বরাবর, DefaultMutableTreeNode দেখুন । এটি জেনেরিক নয়, তবে অন্যথায় এটি বিলটি ফিট করে বলে মনে হচ্ছে। যদিও এটি জাভ্যাক্স.সুইং প্যাকেজে রয়েছে, এটি কোনও এডাব্লুটি বা সুইং ক্লাসের উপর নির্ভর করে না। আসলে, সোর্স কোডটিতে আসলে মন্তব্য রয়েছে// ISSUE: this class depends on nothing in AWT -- move to java.util?


হ্যাঁ, আপনি কিভাবে এই ক্লাস জুড়ে এসেছিলেন?
পেসারিয়ার

7

জাভাতে বেশ কয়েকটি গাছের ডেটা স্ট্রাকচার রয়েছে, যেমন জেডিকে সুইং-এ ডিফল্ট মিউটেবলটি੍ਰੀনোড, স্ট্যানফোর্ড পার্সার প্যাকেজে গাছ এবং অন্যান্য খেলনা কোড। তবে এগুলির কোনওটিই সাধারণ উদ্দেশ্যে যথেষ্ট পর্যাপ্ত নয়।

জাভা-ট্রি প্রকল্প জাভাতে আরও একটি সাধারণ-উদ্দেশ্যে গাছের ডেটা কাঠামো সরবরাহ করার চেষ্টা করে। এই এবং অন্যদের মধ্যে পার্থক্য

  • সম্পূর্ণ বিনামূল্যে। আপনি এটি যে কোনও জায়গায় ব্যবহার করতে পারেন (আপনার হোম ওয়ার্ক ছাড়া: পি)
  • ছোট কিন্তু যথেষ্ট সাধারণ। আমি ডেটা স্ট্রাকচারের সমস্ত কিছু এক ক্লাস ফাইলে রেখেছি, তাই অনুলিপি / পেস্ট করা সহজ হবে।
  • শুধু খেলনা নয়। আমি কয়েক ডজন জাভা ট্রি কোড সম্পর্কে সচেতন যা কেবল বাইনারি গাছ বা সীমিত ক্রিয়াকলাপ পরিচালনা করতে পারে। এই ট্রিনোড এর চেয়ে অনেক বেশি। এটি নোড দেখার জন্য বিভিন্ন উপায়ে সরবরাহ করে যেমন প্রির্ডার, পোস্টর্ডার, ব্রাডফারস্ট, পাতাগুলি, মূলের পাথ ইত্যাদি Moreover এছাড়াও, পুনরুক্তি পর্যাপ্ততার জন্য সরবরাহ করা হয়।
  • আরও ব্যবহার যুক্ত করা হবে। আমি এই প্রকল্পটি বিস্তৃত করতে আরও অপারেশন যুক্ত করতে ইচ্ছুক, বিশেষত আপনি যদি গিথুবের মাধ্যমে একটি অনুরোধ প্রেরণ করেন।


5

যেহেতু প্রশ্নটি কোনও উপলভ্য ডেটা কাঠামোর জন্য জিজ্ঞাসা করে, তালিকা বা অ্যারে থেকে একটি গাছ তৈরি করা যেতে পারে:

Object[] tree = new Object[2];
tree[0] = "Hello";
{
  Object[] subtree = new Object[2];
  subtree[0] = "Goodbye";
  subtree[1] = "";
  tree[1] = subtree;
}

instanceof উপাদানটি একটি সাবট্রি বা টার্মিনাল নোড কিনা তা নির্ধারণ করতে ব্যবহার করা যেতে পারে।


2
বেশ কুৎসিত। এবং কাজ করে না, যদি আপনার ডেটা অবজেক্টগুলি যথাক্রমে তালিকাতে অ্যারে হতে পারে।
ব্যবহারকারী 686249

1
আমি একমত যে এটি কুরুচিপূর্ণ। Objectগুলি পারেন পাত বস্তু (উদাহরণস্বরূপ, হবে Stringগুলি) বা শাখা (অ্যারে দ্বারা প্রতিনিধিত্ব)। এবং এটি কাজ করে: এই কোডটি সংকলন করবে এবং এটি একটি ছোট গাছ তৈরি করবে String
ওলাথে

5
public abstract class Node {
  List<Node> children;

  public List<Node> getChidren() {
    if (children == null) {
      children = new ArrayList<>();
    }
    return chidren;
  }
}

এটি যত সহজ সরল এবং ব্যবহার করা খুব সহজ। এটি ব্যবহার করতে, এটি প্রসারিত করুন:

public class MenuItem extends Node {
  String label;
  String href;
  ...
}

3

উদাহরণ স্বরূপ :

import java.util.ArrayList;
import java.util.List;



/**
 * 
 * @author X2
 *
 * @param <T>
 */
public class HisTree<T> 
{
    private Node<T> root;

    public HisTree(T rootData) 
    {
        root = new Node<T>();
        root.setData(rootData);
        root.setChildren(new ArrayList<Node<T>>());
    }

}

class Node<T> 
{

    private T data;
    private Node<T> parent;
    private List<Node<T>> children;

    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
    public Node<T> getParent() {
        return parent;
    }
    public void setParent(Node<T> parent) {
        this.parent = parent;
    }
    public List<Node<T>> getChildren() {
        return children;
    }
    public void setChildren(List<Node<T>> children) {
        this.children = children;
    }
}

3

অতীতে আমি এর জন্য একটি নেস্টেড মানচিত্র ব্যবহার করেছি। আমি আজ এটি ব্যবহার করি এটি খুব সহজ তবে এটি আমার প্রয়োজনের সাথে খাপ খায়। হতে পারে এটি অন্যকে সাহায্য করবে।

import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * Created by kic on 16.07.15.
 */
public class NestedMap<K, V> {
    private final Map root = new HashMap<>();

    public NestedMap<K, V> put(K key) {
        Object nested = root.get(key);

        if (nested == null || !(nested instanceof NestedMap)) root.put(key, nested = new NestedMap<>());
        return (NestedMap<K, V>) nested;
    }

    public Map.Entry<K,V > put(K key, V value) {
        root.put(key, value);

        return (Map.Entry<K, V>) root.entrySet().stream().filter(e -> ((Map.Entry) e).getKey().equals(key)).findFirst().get();
    }

    public NestedMap<K, V> get(K key) {
        return (NestedMap<K, V>) root.get(key);
    }

    public V getValue(K key) {
        return (V) root.get(key);
    }

    @JsonValue
    public Map getRoot() {
        return root;
    }

    public static void main(String[] args) throws Exception {
        NestedMap<String, Integer> test = new NestedMap<>();
        test.put("a").put("b").put("c", 12);
        Map.Entry<String, Integer> foo = test.put("a").put("b").put("d", 12);
        test.put("b", 14);
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(test));

        foo.setValue(99);
        System.out.println(mapper.writeValueAsString(test));

        System.out.println(test.get("a").get("b").getValue("d"));
    }
}

3

আমি "হাশম্যাপ" এর উপর ভিত্তি করে একটি ছোট "ট্রিম্যাপ" ক্লাস লিখেছি যা যোগ করার পথগুলিকে সমর্থন করে:

import java.util.HashMap;
import java.util.LinkedList;

public class TreeMap<T> extends LinkedHashMap<T, TreeMap<T>> {

    public void put(T[] path) {
        LinkedList<T> list = new LinkedList<>();
        for (T key : path) {
            list.add(key);
        }
        return put(list);
    }

    public void put(LinkedList<T> path) {
        if (path.isEmpty()) {
            return;
        }
        T key = path.removeFirst();
        TreeMap<T> val = get(key);
        if (val == null) {
            val = new TreeMap<>();
            put(key, val);
        }
        val.put(path);
    }

}

এটি "টি" (জেনেরিক) ধরণের জিনিসের একটি গাছ সংরক্ষণ করার জন্য ব্যবহার করা যেতে পারে তবে এটি নোডগুলিতে অতিরিক্ত ডেটা সংরক্ষণ করার জন্য (এখনও) সমর্থন করে না। আপনার যদি এই মত একটি ফাইল থাকে:

root, child 1
root, child 1, child 1a
root, child 1, child 1b
root, child 2
root, child 3, child 3a

তারপরে আপনি এটিকে কার্যকর করে গাছ তৈরি করতে পারেন:

TreeMap<String> root = new TreeMap<>();
Scanner scanner = new Scanner(new File("input.txt"));
while (scanner.hasNextLine()) {
  root.put(scanner.nextLine().split(", "));
}

এবং আপনি একটি সুন্দর গাছ পাবেন। আপনার প্রয়োজনের সাথে খাপ খাইয়ে নেওয়া সহজ হওয়া উচিত।


2

আপনি জাকার্তা প্রকল্পের অংশ অ্যাপাচি জেমেটারের অন্তর্ভুক্ত হ্যাশট্রি ক্লাসটি ব্যবহার করতে পারেন ।

অর্গ.পাচে.জোরফান.কলেকশন প্যাকেজটিতে হ্যাশট্রি ক্লাস অন্তর্ভুক্ত রয়েছে। যদিও এই প্যাকেজটি জেমিটার প্রকল্পের বাইরে প্রকাশিত হয়নি, আপনি এটি সহজেই পেতে পারেন:

1) জেমেটার উত্স ডাউনলোড করুন ।

2) একটি নতুন প্যাকেজ তৈরি করুন।

3) এটিতে / src / jorphan / org / apache / jorphan / সংগ্রহ / অনুলিপি করুন। Data.java বাদে সমস্ত ফাইল

4) এছাড়াও অনুলিপি করুন / এসআরসি / জোজরফান / জর্প / পেচে /জোরফান / উপিল / জোরফান ইউটিলেস.জভা

5) হ্যাশট্রি ব্যবহারের জন্য প্রস্তুত।


2

জাভাতে কোনও নির্দিষ্ট ডেটা কাঠামো নেই যা আপনার প্রয়োজনীয়তার সাথে স্যুট করে। আপনার প্রয়োজনীয়তাগুলি বেশ সুনির্দিষ্ট এবং এর জন্য আপনাকে নিজের ডেটা কাঠামো ডিজাইন করতে হবে। আপনার প্রয়োজনীয়তা দেখে যে কেউ বলতে পারেন যে আপনার নির্দিষ্ট কিছু কার্যকারিতা সহ এক ধরণের এন-অ্যারি গাছের প্রয়োজন। আপনি নিম্নলিখিত উপায়ে আপনার ডেটা স্ট্রাকচার ডিজাইন করতে পারেন:

  1. গাছের নোডের কাঠামো নোডের সামগ্রী এবং বাচ্চাদের তালিকার মতো হবে: শ্রেণি নোড {স্ট্রিংয়ের মান; বাচ্চাদের তালিকা করুন}
  2. আপনাকে প্রদত্ত স্ট্রিংয়ের শিশুদের পুনরুদ্ধার করতে হবে, যাতে আপনার কাছে দুটি পদ্ধতি 1 থাকতে পারে: নোড সার্চনোড (স্ট্রিং স্ট্রিং), প্রদত্ত ইনপুট হিসাবে একই মান রয়েছে এমন নোডটি ফিরিয়ে দেবে (অনুসন্ধানের জন্য বিএফএস ব্যবহার করুন) 2: তালিকা getChildren (স্ট্রিং) স্ট্র): এই পদ্ধতিটি অনুরূপ স্ট্রিংযুক্ত নোডটি পেতে অভ্যন্তরীণভাবে সার্চনোডকে কল করবে এবং তারপরে এটি শিশুদের সমস্ত স্ট্রিং মানগুলির তালিকা তৈরি করবে এবং ফিরে আসবে।
  3. আপনার গাছে একটি স্ট্রিং toোকাতেও হবে। আপনাকে একটি পদ্ধতি লিখতে হবে বলুন শূন্য রোধ সন্নিবেশ (স্ট্রিং প্যারেন্ট, স্ট্রিং মান): এটি আবার পিতামাতার সমান মানযুক্ত নোডটি অনুসন্ধান করবে এবং তারপরে আপনি প্রদত্ত মান সহ একটি নোড তৈরি করতে পারেন এবং খুঁজে পাওয়া পিতামাতার বাচ্চাদের তালিকায় যুক্ত করতে পারেন ।

আমি পরামর্শ দেব, আপনি ক্লাস নোডের মতো এক শ্রেণিতে নোডের কাঠামো লিখুন ring স্ট্রিং মান; বাচ্চাদের তালিকাবদ্ধ করুন;} এবং অন্যান্য সমস্ত পদ্ধতি যেমন অনুসন্ধান, সন্নিবেশ করান এবং শিশুদের অন্য নোড ইউটিলেস ক্লাসে সন্ধান করুন যাতে আপনি গাছের গোড়াটি নির্দিষ্ট গাছের উপর অপারেশন করার জন্য যেমন ক্লাস নোড ইউটিলস {পাবলিক স্ট্যাটিক নোড অনুসন্ধান (নোড রুট, স্ট্রিং মান) সরবরাহ করতে পারেন {// বিএফএস সম্পাদন করুন এবং নোড ফেরান}


2
    // TestTree.java
// A simple test to see how we can build a tree and populate it
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;

public class TestTree extends JFrame {

  JTree tree;
  DefaultTreeModel treeModel;

  public TestTree( ) {
    super("Tree Test Example");
    setSize(400, 300);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public void init( ) {
    // Build up a bunch of TreeNodes. We use DefaultMutableTreeNode because the
    // DefaultTreeModel can use it to build a complete tree.
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
    DefaultMutableTreeNode subroot = new DefaultMutableTreeNode("SubRoot");
    DefaultMutableTreeNode leaf1 = new DefaultMutableTreeNode("Leaf 1");
    DefaultMutableTreeNode leaf2 = new DefaultMutableTreeNode("Leaf 2");

    // Build our tree model starting at the root node, and then make a JTree out
    // of it.
    treeModel = new DefaultTreeModel(root);
    tree = new JTree(treeModel);

    // Build the tree up from the nodes we created.
    treeModel.insertNodeInto(subroot, root, 0);
    // Or, more succinctly:
    subroot.add(leaf1);
    root.add(leaf2);

    // Display it.
    getContentPane( ).add(tree, BorderLayout.CENTER);
  }

  public static void main(String args[]) {
    TestTree tt = new TestTree( );
    tt.init( );
    tt.setVisible(true);
  }
}

3
দয়া করে কেবল কোড ডাম্প করবেন না - এটি কী করে তা ব্যাখ্যা করুন এবং বিশেষত এটি অন্যান্য উত্তরগুলির চেয়ে কেন আলাদা (ভাল)।
জান ডোগজেন

2

আমি একটি ট্রি লাইব্রেরি লিখেছি যা জাভা 8 এর সাথে দুর্দান্তভাবে খেলছে এবং এর কোনও অন্যান্য নির্ভরতা নেই। এটি কার্যকরী প্রোগ্রামিং থেকে কিছু ধারণার আলগা ব্যাখ্যাও দেয় এবং আপনাকে পুরো গাছ বা সাবট্রিগুলিকে মানচিত্র / ফিল্টার / ছাঁটাই / অনুসন্ধান করতে দেয়।

https://github.com/RutledgePaulV/prune

প্রয়োগটি সূচকের সাথে বিশেষ কিছু করে না এবং আমি পুনরাবৃত্তি থেকে দূরে সরে যাইনি, তাই এটি সম্ভব যে বড় গাছের পারফরম্যান্স হ্রাস পাবে এবং আপনি স্ট্যাকটি ফুঁকতে পারবেন। তবে আপনার যা যা প্রয়োজন তা হ'ল ছোট থেকে মাঝারি গভীরতার একটি সোজা গাছ, আমি মনে করি এটি যথেষ্ট ভাল কাজ করে। এটি সমতার সংক্ষিপ্ত (মান ভিত্তিক) সংজ্ঞা সরবরাহ করে এবং এটিতে একটি টস্ট্রিং বাস্তবায়ন রয়েছে যা আপনাকে বৃক্ষটি কল্পনা করতে দেয়!


1

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

package com.datastructure.tree;

public class BinaryTreeWithoutRecursion <T> {

    private TreeNode<T> root;


    public BinaryTreeWithoutRecursion (){
        root = null;
    }


    public void insert(T data){
        root =insert(root, data);

    }

    public TreeNode<T>  insert(TreeNode<T> node, T data ){

        TreeNode<T> newNode = new TreeNode<>();
        newNode.data = data;
        newNode.right = newNode.left = null;

        if(node==null){
            node = newNode;
            return node;
        }
        Queue<TreeNode<T>> queue = new Queue<TreeNode<T>>();
        queue.enque(node);
        while(!queue.isEmpty()){

            TreeNode<T> temp= queue.deque();
            if(temp.left!=null){
                queue.enque(temp.left);
            }else
            {
                temp.left = newNode;

                queue =null;
                return node;
            }
            if(temp.right!=null){
                queue.enque(temp.right);
            }else
            {
                temp.right = newNode;
                queue =null;
                return node;
            }
        }
        queue=null;
        return node; 


    }

    public void inOrderPrint(TreeNode<T> root){
        if(root!=null){

            inOrderPrint(root.left);
            System.out.println(root.data);
            inOrderPrint(root.right);
        }

    }

    public void postOrderPrint(TreeNode<T> root){
        if(root!=null){

            postOrderPrint(root.left);

            postOrderPrint(root.right);
            System.out.println(root.data);
        }

    }

    public void preOrderPrint(){
        preOrderPrint(root);
    }


    public void inOrderPrint(){
        inOrderPrint(root);
    }

    public void postOrderPrint(){
        inOrderPrint(root);
    }


    public void preOrderPrint(TreeNode<T> root){
        if(root!=null){
            System.out.println(root.data);
            preOrderPrint(root.left);
            preOrderPrint(root.right);
        }

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BinaryTreeWithoutRecursion <Integer> ls=  new BinaryTreeWithoutRecursion <>();
        ls.insert(1);
        ls.insert(2);
        ls.insert(3);
        ls.insert(4);
        ls.insert(5);
        ls.insert(6);
        ls.insert(7);
        //ls.preOrderPrint();
        ls.inOrderPrint();
        //ls.postOrderPrint();

    }

}

2
" সংগ্রহের ক্লাস ব্যবহার না করে " আহ? তাহলে কুই ক্লাসটি কোথা থেকে এসেছে? এবং উপরে যেমন বলা হয়েছে, এটি একটি বাইনারি গাছ, প্রথম প্রয়োজনে ব্যর্থ হয় (যে কোনও সংখ্যক শিশু নোড)।
ফিলিহো

1

আপনি java.util। * তে ট্রিসেট ক্লাস ব্যবহার করতে পারেন। এটি বাইনারি অনুসন্ধান গাছের মতো কাজ করছে, সুতরাং এটি ইতিমধ্যে বাছাই করা হয়েছে। ট্রিসেট বর্গটি পরিবেশনযোগ্য, সংগ্রহ এবং সেট ইন্টারফেস প্রয়োগ করে। আপনি সেটের মতো পুনরাবৃত্তকারী সহ গাছের মধ্য দিয়ে যেতে পারেন।

TreeSet<String> treeSet = new TreeSet<String>();
Iterator<String> it  = treeSet.Iterator();
while(it.hasNext()){
...
}

আপনি চেক করতে পারেন, জাভা ডক এবং অন্য কিছু ।


-1

সংগ্রহ কাঠামোটি ব্যবহার না করে কাস্টম ট্রি ট্রি প্রয়োগ করে। এটি বৃক্ষ বাস্তবায়নে প্রয়োজনীয় বিভিন্ন মৌলিক অপারেশন রয়েছে।

class Node {

    int data;
    Node left;
    Node right;

    public Node(int ddata, Node left, Node right) {
        this.data = ddata;
        this.left = null;
        this.right = null;      
    }

    public void displayNode(Node n) {
        System.out.print(n.data + " "); 
    }

}

class BinaryTree {

    Node root;

    public BinaryTree() {
        this.root = null;
    }

    public void insertLeft(int parent, int leftvalue ) {
        Node n = find(root, parent);
        Node leftchild = new Node(leftvalue, null, null);
        n.left = leftchild;
    }

    public void insertRight(int parent, int rightvalue) {
        Node n = find(root, parent);
        Node rightchild = new Node(rightvalue, null, null);
        n.right = rightchild;
    }

    public void insertRoot(int data) {
        root = new Node(data, null, null);
    }

    public Node getRoot() {
        return root;
    }

    public Node find(Node n, int key) {     
        Node result = null;

        if (n == null)
            return null;

        if (n.data == key)
            return n;

        if (n.left != null)
            result = find(n.left, key);

        if (result == null)
            result = find(n.right, key);

        return result;
    } 

    public int getheight(Node root){
        if (root == null)
            return 0;

        return Math.max(getheight(root.left), getheight(root.right)) + 1; 
    }

    public void printTree(Node n) {     
        if (n == null)
            return;

        printTree(n.left);
        n.displayNode(n);
        printTree(n.right);             
    }

}

11
এটি একটি বাইনারি গাছ, এটি
ওপির
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.