/*
         * add (S, x):
         * Adds the element x to a set S, if it is not present already.
         * No return value.
         */
        static void add(ref SetList S, int x)
        {
            /* if the element is already in the list,
             * or if it is equal or less than zero,
             * it will not be added to the list */
            if (is_element_of(x, S) || x <= 0) {
                return;
            }

            /* Creates a new node
             * and fills it with value x
             */
            SetNode add = new SetNode();
            add.data = x;

            /* If the list is empty,
             * add it as first node in the list
             */
            if (is_empty(S)) {
                S.first = add;
            }

            /* If the list isn't empty,
             * Iterate through list until the end
             * and add the new node */
            else {

                SetNode node = S.first;
                while (node.next != null) {
                    node = node.next;
                }
                node.next = add;
            }
        }
 /*
  * capacity( S ):
  * returns the maximum number of values that S can hold.
  */
 static int capacity(SetList S)
 {
     /* As a dynamic data structure a LinkedList doesn't have any hard limit on the capacity
      * It's limited to the current size of the structure, with a maximum potential capacity
      * defined by the pool of available memory.
      * The maximum potential capacity could be calculated by filling a list until a
      * System.OutOfMemoryException is thrown, and counting the number of values added.
      */
     return size(S);
 }
 /*
  * symmetric_difference ( S, T ):
  * returns the "symmetric difference" of S and T,
  * i.e., the union of difference(S, T) and difference(T, S)
  */
 static SetList symmetricDifference(SetList s, SetList t)
 {
     return union(difference(s, t), difference(t, s));
 }
 /*
  * size( S ):
  * returns the number of elements in S
  */
 static int size(SetList S)
 {
     /* Start counter at 0 */
     int size = 0;
     SetNode node = S.first;
     /* Iterate through each value in set
      * increasing counter by 1 each time
      */
     while (node != null) {
         size++;
         node = node.next;
     }
     /* Return final counter */
     return size;
 }
 /*
  * remove(S, x):
  * this function removes the element x from the set S.
  * No return value.
  */
 static void remove(ref SetList s, int x)
 {
     SetNode node = s.first;
     /* Check the very first node
      * If it contains the value to remove then
      * replace the current first node with the one afterwards
      */
     if (node.data == x) s.first = node.next;
     else
     /* Otherwise iterate through all values in set
      * until end of set
      */ {
         while (node.next != null) {
             /* Unless the next node contains the value to remove */
             if (node.next.data == x) {
                 /* In which case, set the next node to the one
                  * afterwards, removing the next node  */
                 node.next = node.next.next;
                 /* and end the function, job done */
                 return;
             }
             /* Next iteration */
             node = node.next;
         }
     }
 }
        /* Print_subset
         * Copy of standard print(), just without newlines when writing to console.
         * Pretty much just here to make printing powersets prettier.
         */
        static void print_subset(SetList S)
        {
            if (is_empty(S)) {
                Console.Write("{ }");
                return;
            }
            SetNode node = S.first;

            System.Console.Write("{ ");

            while (node != null) {
                System.Console.Write(node.data + ", ");
                node = node.next;
            }

            System.Console.Write("}");
        }
 /*
  * print( S ):
  * prints a list of the elements of S in order added
  */
 static void print(SetList S)
 {
     /* If set is empty, then print default set {}
      * and end function
      */
     if (is_empty(S)) {
         Console.WriteLine("{ }");
         return;
     }
     /* Otherwise iterate through values
      * and output each one in turn
      */
     SetNode node = S.first;
     System.Console.Write("{ ");
     while (node != null) {
         System.Console.Write(node.data + ", ");
         node = node.next;
     }
     System.Console.WriteLine("}");
 }
 /*
  * copy_set ( S ):
  * Instantiates a new SetList instance with the same values as S.
  * Returns the new instance.
  */
 static SetList copy_set(SetList S)
 {
     SetList newList = new SetList();
     newList = S;
     return newList;
 }
        static void Main()
        {
            //variable declaration
            SetList S = new SetList();
            Console.Write("Set S: ");
            print(S);
            Console.WriteLine();

            //checks whether the list is empty (should be "true")
            System.Console.WriteLine("is_empty(S): " + is_empty(S));
            Console.WriteLine();
            add(ref S, 1);
            add(ref S, 2);
            add(ref S, 3);
            add(ref S, 4);
            add(ref S, 5);
            add(ref S, 6);
            add(ref S, 7);
            add(ref S, 19);
            System.Console.Write("After adding " + size(S) + " values to set S: ");
            print(S);
            Console.WriteLine();

            System.Console.WriteLine("Size of S: " + size(S));
            Console.WriteLine();

            System.Console.WriteLine("is_empty(S): " + is_empty(S));
            Console.WriteLine();

            SetList T = new SetList();
            add(ref T, 1);
            add(ref T, 2);
            add(ref T, 4);
            add(ref T, 5);
            add(ref T, 8);
            System.Console.Write("Set T: ");
            print(T);
            Console.WriteLine();

            System.Console.WriteLine("Size of T: " + size(T));
            Console.WriteLine();

            Console.WriteLine("Is 3 in set T? " + is_element_of(3, T));
            Console.WriteLine();

            Console.Write("Set S after removing some elements:");
            remove(ref S, 1);
            remove(ref S, 4);
            remove(ref S, 6);
            print(S);
            Console.WriteLine();

            Console.WriteLine("Is 7 in set S? " + is_element_of(7, S));
            Console.WriteLine();

            Console.WriteLine("X = copy_set(S). Set X:");
            SetList X = copy_set(S);
            print(X);
            Console.WriteLine();

            Console.WriteLine("Is S a subset of T? " + is_subset(S, T));
            Console.WriteLine();

            Console.WriteLine("union(S, T): ");
            print(union(S, T));

            Console.WriteLine("intersection(S, T): ");
            print(intersection(S, T));

            Console.WriteLine("difference(S, T): ");
            print(difference(S, T));

            Console.WriteLine("difference(T, S): ");
            print(difference(T, S));

            Console.WriteLine("symmetricDifference(S, T): ");
            print(symmetricDifference(S, T));
            SetList Y = new SetList();
            PowersetList test = new PowersetList();
            Console.Write("Powerset({}): ");
            PowersetList PS = new PowersetList();
            PS = PowerSet(Y);
            print(PS);
            add(ref Y, 1);
            add(ref Y, 2);
            add(ref Y, 3);
            add(ref Y, 4);
            add(ref Y, 5);
            add(ref Y, 6);
            Console.Write("Powerset({1,2,3,4,5,6}): ");
            print(PowerSet(Y));
            Console.ReadLine();
        }
 /*
  * is_subset( S,  T):
  * tests whether the set S is a subset of set T.
  * Returns a Boolean value, accordingly.
  */
 static Boolean is_subset(SetList S, SetList T)
 {
     //Start at first node
     SetNode node = S.first;
     //Iterate through all values of S
     while (node.next != null) {
         //If a value of S isn't in T, then not a subset
         if (!is_element_of(node.data, T))
         //so return false
         return false;
         //Continue to next node
         node = node.next;
     }
     //If loop completes without returning false,
     //All values of S are in T, therefore
     //S is a subset
     return true;
 }
 /*
  * is_empty( S ):
  * checks whether the set S is empty;
  * returns the Boolean value true or false, accordingly.
  */
 static Boolean is_empty(SetList S)
 {
     /* Checks if the list has an initial value
      */
     return (S.first == null);
 }
 /*
  * is_element_of ( x, S ):
  * checks whether the value x is in the set S;
  * returns true or false, accordingly.
  */
 static Boolean is_element_of(int x, SetList S)
 {
     /* Iterate through all values */
     SetNode node = S.first;
     while (node != null)
     /* If value is equal to search, then return true */
     if (node.data == x) return true;
     /* Otherwise continue iterating */
     else node = node.next;
     /* If all values are searched, without finding the value
      * then value isn't in set, so return false */
     return false;
 }
 /*
  * intersection(  S,  T):
  * returns the intersection of sets S and T.
  */
 static SetList intersection(SetList S, SetList T)
 {
     SetNode node = S.first;
     SetList intersection = new SetList();
     /* Iterate through all values in set */
     while (node != null) {
         /* If value is in both sets,
          * then add to intersection set */
         if (is_element_of(node.data, T)) {
             add(ref intersection, node.data);
         }
         node = node.next;
     }
     /* Return final intersection set */
     return intersection;
 }
 /*
  * difference(  S,  T ):
  * returns the "difference" of sets S and T, all values in S that are not in T.
  */
 static SetList difference(SetList S, SetList T)
 {
     SetNode node = S.first;
     SetList diff = new SetList();
     /* Iterate through all values in set */
     while (node != null) {
         /* If element is in S but not T
          * then add it to the differences set.
          */
         if (!is_element_of(node.data, T)) {
             add(ref diff, node.data);
         }
         node = node.next;
     }
     /* Return final set of differences */
     return diff;
 }
        /*
         * union(  S,  T ):
         * returns the "union" of sets S and T
         */
        static SetList union(SetList S, SetList T)
        {
            SetNode node_s = new SetNode();
            node_s = S.first;
            SetNode node_t = new SetNode();
            node_t = T.first;
            /* New SetList container for resulting set */
            SetList union = new SetList();
            /* adds elements of set S to the union set */
            while (node_s != null) {
                /* Potential duplicates are already handled by the add() procedure */
                add(ref union, node_s.data);
                /* Go to next iteration */
                node_s = node_s.next;
            }

            /* Add all elements from set T to union set */
            while (node_t != null) {
                add(ref union, node_t.data);
                node_t = node_t.next;
            }
            /* Return the final list */
            return union;
        }
        /* Actual powerset generation function
         * Returns a PowersetList object containing each possible subset
         * possible to generate from the given set
         */
        static PowersetList PowerSet(SetList S)
        {
            /* How many values do we have in original set?
             * This will affect length of powerset
             * We create an array with this length to hold values from the set
             * which simplifies our algorithm later
             */
            int len = size(S);
            int[] vals = new int[len];
            int counter = 0;
            SetNode node = S.first;
            /* Iterate through values in set,
             * adding each to the array
             */
            while (node != null) {
                vals[counter++] = node.data;
                node = node.next;
            }
            /* At this point, vals[] contains all our set values.
             * We set up our list container class, and our first node.
             * Even if there are no values in given set, we still want the empty set {}
             * so we set that as our first subset.
             */
            PowersetList powerset = new PowersetList();
            PowersetNode prev_node = new PowersetNode();
            prev_node.data = new SetList();
            powerset.first = prev_node;
            /* Calculate power-set length using 2^N where N = number of values.
             * Math.Pow isn't C-Core so we created a simple power function for this
             */
            int n = pow(2, len);
            /* Our empty set {} is at location 0, so we start the loop at 1
             * then loop through until we have n values.
             */
            for (int x = 1; x < n; x++) {
                /* Set up this sub-set's containers */
                PowersetNode New_Node = new PowersetNode();
                New_Node.data = new SetList();
                /* Now iterate through each value in our vals[] array */
                for (int i = 0; i < len; i++) {
                    /* If it should be in this subset, then we add it to the current subset.
                     * This is done by using the bitwise operators & and << to check if
                     * the binary conversion of x AND 1 << i is greater than 0. */
                    if ((x & (1 << i)) > 0) {
                        add(ref New_Node.data, vals[i]);
                    }
                }
                /* Finally, add our completed subset to the previous node's next
                 */
                prev_node.next = New_Node;
                prev_node = prev_node.next;
            }

            return powerset;
        }
 /*
  * Task 1 Functions - Basic Set functions
  * Implemented using a simple LinkedList data structure
  */
 /*
  * clear_set ( S ):
  * removes all elements from the set;
  * returns nothing
  */
 static void clear_set(ref SetList S)
 {
     /* Sets the initial node of a list to empty
      */
     S.first = null;
 }