Problem:
Stable Sort

Let's arrange a deck of cards. There are totally 36 cards of 4 suits(S, H, C, D) and 9 values (1, 2, ... 9). For example, 'eight of heart' is represented by H8 and 'one of diamonds' is represented by D1.

Your task is to write a program which sorts a given set of cards in ascending order by their values using the Bubble Sort algorithms and the Selection Sort algorithm respectively. These algorithms should be based on the following pseudocode:

BubbleSort(C)
1 for i = 0 to C.length-1
2 for j = C.length-1 downto i+1
3 if C[j].value < C[j-1].value
4 swap C[j] and C[j-1]

SelectionSort(C)
1 for i = 0 to C.length-1
2 mini = i
3 for j = i to C.length-1
4 if C[j].value < C[mini].value
5 mini = j
6 swap C[i] and C[mini]

Note that, indices for array elements are based on 0-origin.

For each algorithm, report the stability of the output for the given input (instance). Here, 'stability of the output' means that: cards with the same value appear in the output in the same order as they do in the input (instance).

Input

The first line contains an integer N, the number of cards.

N cards are given in the following line. Each card is represented by two characters. Two consecutive cards are separated by a space character.

Output

In the first line, print the arranged cards provided by the Bubble Sort algorithm. Two consecutive cards should be separated by a space character.

In the second line, print the stability ("Stable" or "Not stable") of this output.

In the third line, print the arranged cards provided by the Selection Sort algorithm. Two consecutive cards should be separated by a space character.

In the fourth line, print the stability ("Stable" or "Not stable") of this output.

Constraints

1 ≤ N ≤ 36

Sample Input 1

5
H4 C9 S4 D2 C3

Sample Output 1

D2 C3 H4 S4 C9
Stable
D2 C3 S4 H4 C9
Not stable

Sample Input 2

2
S1 H1

Sample Output 2

S1 H1
Stable
S1 H1
Stable

Solution in C# (judge verdict: Accepted)

using Extention;
// optional
using IOUtil;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;

public static class Program {
    [Serializable]
    class Card {
        public string Raw { get; }
        public int Value { get; }

        public Card(string raw) {
            Raw = raw;
            Value = int.Parse(new string(raw.Skip(1).ToArray()));
        }
    }

    public static void Main() {
        #region SetAutoFlushIsFalse
#if !DEBUG
        var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
        Console.SetOut(sw);
#endif
        #endregion

        var n = ReadLib.ReadAsInt();

        var cards = Console.ReadLine().Split(' ').Select(e => new Card(e)).ToArray();

        var bubble = BubbleSort(cards);
        Console.WriteLine(string.Join(" ", bubble.Select(e => e.Raw).ToArray()));
        Console.WriteLine(IsStable(cards, bubble) ? "Stable" : "Not stable");

        var selection = SelectionSort(cards);
        Console.WriteLine(string.Join(" ", selection.Select(e => e.Raw).ToArray()));
        Console.WriteLine(IsStable(cards, selection) ? "Stable" : "Not stable");

        #region Flush
#if !DEBUG
        Console.Out.Flush();
        sw.Close();
#endif
        #endregion
    }

    private static bool IsStable(Card[] raw, Card[] target) {
        for (int i = 0; i < raw.Length; i++) {
            for (int j = i + 1; j < raw.Length; j++) {
                for (int a = 0; a < target.Length; a++) {
                    for (int b = a + 1; b < target.Length; b++) {
                        if (raw[i].Value == raw[j].Value && raw[i].Raw == target[b].Raw && raw[j].Raw == target[a].Raw) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    private static Card[] SelectionSort(Card[] raw) {
        var cards = raw.DeepCopy();

        for (int i = 0; i < cards.Length; i++) {
            var minj = i;
            for (int j = i; j < cards.Length; j++) {
                if (cards[minj].Value > cards[j].Value) {
                    minj = j;
                }
            }

            if (minj != i) {
                cards.Swap(minj, i);
            }
        }

        return cards;
    }

    private static Card[] BubbleSort(Card[] raw) {
        var cards = raw.DeepCopy();

        for (int i = 0; i < cards.Length; i++) {
            for (int j = cards.Length - 1; j >= i + 1; j--) {
                if (cards[j].Value < cards[j - 1].Value) {
                    cards.Swap(j, j - 1);
                }
            }
        }

        return cards;
    }
}

namespace IOUtil {
    static class ReadLib {
        public static long ReadAsLong() {
            return long.Parse(Console.ReadLine());
        }

        public static int ReadAsInt() {
            return int.Parse(Console.ReadLine());
        }

        public static int[] ReadAsIntArray(int step = 0) {
            return Console.ReadLine().Split(' ').Select(s => int.Parse(s) + step).ToArray();
        }

        public static long[] ReadAsLongArray(int step = 0) {
            return Console.ReadLine().Split(' ').Select(s => long.Parse(s) + step).ToArray();
        }

        public static ulong[] ReadAsULongArray() {
            return Console.ReadLine().Split(' ').Select(s => ulong.Parse(s)).ToArray();
        }

        public static string[] ReadAsStringArray() {
            return Console.ReadLine().Split(' ');
        }

        public static int[] ReadNTimesAsInt(int n, int step = 0) {
            return Enumerable.Range(1, n).Select(s => int.Parse(Console.ReadLine()) + step).ToArray();
        }

        public static char[][] ReadNTimesAsCharArray(int n) {
            return Enumerable.Range(1, n).Select(i => Console.ReadLine().ToArray()).ToArray();
        }

        public static long[] ReadNTimesAsLong(int n, int step = 0) {
            return Enumerable.Range(1, n).Select(s => long.Parse(Console.ReadLine()) + step).ToArray();
        }

        public static int[][] ReadNTimesAsIntArray(int n, int step = 0) {
            return Enumerable.Range(1, n).Select(s => ReadAsIntArray(step)).ToArray();
        }

        public static string[] ReadNTimesAsString(int n) {
            return Enumerable.Range(1, n).Select(s => Console.ReadLine()).ToArray();
        }
    }
}

namespace Heaps {
    /// <summary>優先度付きキュー</summary>
    public class PriorityQueue<T> : IEnumerable<T>, IReadOnlyCollection<T> where T : IComparable<T> {
        public List<T> HeapArray { get; }
        public T NIL { get; }
        public bool IsMax { get; }

        public int Count => HeapArray.Count;

        /// <param name="heapArray">ヒープ</param>
        /// <param name="NIL">NILの値</param>
        /// <param name="IsMax">True時：大きい方から取り出す、False時：小さい方から取り出す</param>
        public PriorityQueue(T NIL, IEnumerable<T> heapArray = null, bool IsMax = true) {
            this.HeapArray = heapArray == null ? new List<T>() : heapArray.ToList();
            this.NIL = NIL;
            this.IsMax = IsMax;
            Update();
        }

        /// <summary>KeyのValueを取得</summary>
        public T this[int id] {
            get {
                if (id <= 0 || id > HeapArray.Count) {
                    return NIL;
                }

                return HeapArray[id - 1];
            }
        }

        class Node {
            public int Key { get; }
            public T Value => outer[Key];
            readonly PriorityQueue<T> outer;

            public Node(int key, PriorityQueue<T> outer) {
                Key = key;
                this.outer = outer;
            }

            public Node Left {
                get {
                    var leftKey = 2 * Key;
                    return new Node(leftKey, outer);
                }
            }

            public Node Right {
                get {
                    var rightkey = 2 * Key + 1;
                    return new Node(rightkey, outer);
                }
            }

            public Node Parent {
                get {
                    var parentKey = Key / 2;
                    return new Node(parentKey, outer);
                }
            }
        }

        private Node GetNode(int key) {
            return new Node(key, this);
        }

        /// <summary>max Heap木とする O(N)</summary>
        public void Update() {
            var n = HeapArray.Count() / 2;
            /// <summary>葉から順に処理を行う</summary>
            for (int i = n; i >= 1; i--) {
                Heapify(i);
            }
        }

        /// <summary>idを根とする部分木について、Heap木を維持したまま、idを下降させる</summary>
        private void Heapify(int key) {
            var current = GetNode(key);

            var left = current.Left;
            var right = current.Right;

            var largest = current;
            var sign = IsMax ? 1 : -1;
            if (left.Value.CompareTo(NIL) != 0 && left.Value.CompareTo(current.Value) * sign > 0) {
                largest = left;
            }

            if (right.Value.CompareTo(NIL) != 0 && right.Value.CompareTo(largest.Value) * sign > 0) {
                largest = right;
            }

            if (largest.Key != key) {
                HeapArray.Swap(key - 1, largest.Key - 1);   // 元と異なるときはSwapする
                Heapify(largest.Key); // largest.Key は元のkeyの場所。葉で更にMaxHeaptyを行う。
            }
        }

        /// <summary>keyの値を挿入する</summary>
        public void Enqueue(T value) {
            HeapArray.Add(value);

            var inserted = GetNode(HeapArray.Count);    // 末尾に挿入
            var parent = inserted.Parent;
            var sign = IsMax ? 1 : -1;

            // 挿入Nodeが根になる or 親 > 子になるまで親とNodeを交換
            while (inserted.Key > 1 && value.CompareTo(parent.Value) * sign > 0) {
                HeapArray.Swap(inserted.Key - 1, parent.Key - 1);
                inserted = parent;
                parent = inserted.Parent;
            }
        }

        public T Dequeue() {
            if (HeapArray.Count == 0) {
                return NIL;
            }

            var popVal = HeapArray.First();
            var newRootVal = HeapArray.Last();  // 新しい根となる。

            HeapArray.RemoveAt(HeapArray.Count - 1);    // del last

            if (HeapArray.Count > 0) {
                HeapArray[0] = newRootVal;
                Heapify(1);
            }

            return popVal;
        }

        public T Peek() {
            return HeapArray.First();
        }

        public IEnumerator<T> GetEnumerator() {
            while (HeapArray.Count > 0) {
                yield return Dequeue();
            }
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        public void Clear() {
            HeapArray.Clear();
        }

        public bool Contains(T val) {
            return HeapArray.Contains(val);
        }

        public PriorityQueue<T> Clone() {
            return new PriorityQueue<T>(NIL, HeapArray.DeepCopy());
        }
    }
}

namespace Extention {
    /// <summary>拡張メソッドs</summary>
    static class MyExtention {
        /// <summary>iとjを入れ替える</summary>
        public static void Swap<T>(this T[] arr, int i, int j) {
            var buf = arr[i];
            arr[i] = arr[j];
            arr[j] = buf;
        }

        public static void Swap<T>(this List<T> list, int i, int j) {
            var buf = list[i];
            list[i] = list[j];
            list[j] = buf;
        }

        /// <summary>
        /// partition。末尾sArr[r]を基準として、左に基準より小さい数、右に基準より大きい数が存在するように配列を並び替える。
        /// </summary>
        /// <param name="sArr"></param>
        /// <param name="p">partitionの先頭の添字</param>
        /// <param name="r">partitionの末尾の添字</param>
        /// <returns>partitionの基準が存在する添字</returns>
        public static int Partition(this int[] sArr, int p, int r) {
            var x = sArr[r];
            var i = p - 1;
            for (int j = p; j < r; j++) {
                if (sArr[j] <= x) {
                    i++;
                    sArr.Swap(i, j);
                }
            }
            sArr.Swap(i + 1, r);
            return i + 1;
        }

        /// <summary>深いコピーをする</summary>
        public static T DeepCopy<T>(this T obj) {
            T result;
            var b = new BinaryFormatter();
            using (var mem = new MemoryStream()) {
                b.Serialize(mem, obj); //  binaryFormatterによりobjをmemにserial化して書き出す
                mem.Position = 0; // memのpotisionを先頭に戻す
                result = (T)b.Deserialize(mem); // memの内容を読み取る。
            }
            return result;
        }

        public static string Left(this string str, int length) {
            return str.Substring(0, length);
        }

        public static string Right(this string str, int length) {
            return str.Substring(str.Length - length, length);
        }

        public static int Find<T>(this T[] array, T obj) {
            return Array.IndexOf(array, obj);
        }

        public static int LastFind<T>(this T[] array, T obj) {
            return Array.LastIndexOf(array, obj);
        }
    }
}

static class MyMath {
    /// <summary>階乗</summary>
    public static long Factorial(int n) {
        if (n == 0) {
            return 1;
        }

        return Permutation(n, 0);
    }

    public static long Permutation(int n, int k) {
        return Enumerable.Range(0, n - k).Select(i => n - i).Aggregate(1, (b, i) => b * i);
    }

    #region FullPower
    /// <summary>総乗、π</summary>
    public static long FullPower(IEnumerable<long> vs) {
        return vs.Aggregate(1L, (a, b) => a * b);
    }

    public static long FullPower(IEnumerable<int> vs) {
        return vs.Aggregate(1L, (a, b) => a * b);
    }
    #endregion

    /// <summary>最大公約数</summary>
    public static long Gcd(long item1, long item2) {
        var a = Math.Max(item1, item2);
        var b = Math.Min(item1, item2);

        while (true) {
            long mod;
            Math.DivRem(a, b, out mod);
            if (mod == 0) {
                break;
            }

            a = b;
            b = mod;
        }
        return b;
    }

    /// <summary>約分。最大公約数で割ったものを返す。</summary>
    public static Tuple<long, long> DeviedByGcd(long item1, long item2) {
        var gcd = Gcd(item1, item2);
        return new Tuple<long, long>(item1 / gcd, item2 / gcd);
    }

    public static long Lcm(int item1, int item2) {
        return Math.BigMul(item1, item2) / Gcd(item1, item2);
    }

    public static ModCombination ModCombination(int maxN, int mod = 1000000007) {
        return new ModCombination(maxN, mod);
    }

    /// <summary>a^n mod</summary>
    public static int ModPow(long a, long n, int mod = 1000000007) {
        long res = 1;
        long pow = a;

        while (n > 0) {
            if ((n & 1) == 1) {
                res = (pow * res) % mod;    // resにaをかける
            }

            pow = (pow * pow) % mod;    // 次のaはa^2
            n >>= 1;
        }

        return (int)res;
    }
}

static class MyMethod {
    /// <summary>数え上げて、key, 出現回数に変換</summary>
    public static Dictionary<T, int> CountUp<T>(IEnumerable<T> str) {
        return
            str
            .GroupBy(c => c)
            .Select(g => new KeyValuePair<T, int>(g.Key, g.Count()))
            .ToDictionary(e => e.Key, e => e.Value);
    }

    /// <summary>ある要素を持つindexをすべて返す</summary>
    public static int[] InducesOfValue<T>(this T[] arr, T searchValue) {
        return arr
            .Select((v, i) => new { v, i })
            .Where(o => searchValue.Equals(o.v))
            .Select(o => o.i)
            .ToArray();
    }

    /// <summary>ある要素を持つindexをすべて返す</summary>
    public static int[] Induces<T>(this IEnumerable<T> arr, T searchValue) {
        return arr.ToArray().InducesOfValue(searchValue);
    }
}

/// <summary>組み合わせ</summary>
class ModCombination {
    private int mod;
    private int[] fac;
    private int[] finv;
    private int[] inv;

    public ModCombination(int max, int mod = 1000000007) {
        this.mod = mod;
        fac = new int[max]; // modが法のn!の列

        inv = new int[max]; // indexの逆元の列
        finv = new int[max]; // modを法とした、invの累積の累積

        fac[0] = 1; fac[1] = 1;
        finv[0] = 1; finv[1] = 1;
        inv[1] = 1;

        for (int i = 2; i < max; i++) {
            fac[i] = (int)(Math.BigMul(fac[i - 1], i) % mod);  // factorを求める
            var s = Math.BigMul(inv[mod % i], mod / i) % mod;
            inv[i] = (int)(mod - s);　 // iに対する逆元を求める
            finv[i] = (int)(Math.BigMul(finv[i - 1], inv[i]) % mod);
        }
    }
    /// <summary>nCk</summary>
    public int Calculation(int n, int k) {
        if (n < k) return 0;
        if (n < 0 || k < 0) return 0;

        return (int)(Math.BigMul(fac[n], (int)(Math.BigMul(finv[k], finv[n - k]) % mod)) % mod);
    }
}

/// <summary>あまりを計算するためのintのラッパー</summary>
struct ModInt {
    int Value { get; }
    int Mod { get; }

    public override string ToString() {
        return Value.ToString();
    }

    public static explicit operator ModInt(long value) {
        return new ModInt(value);
    }

    public ModInt(long value, int mod = 1000000007) {
        this.Value = (int)(value % mod);
        this.Mod = mod;
    }

    public static explicit operator int(ModInt modInt) {
        return modInt.Value;
    }

    private static void CheckNotEqualMod(ModInt item1, ModInt item2) {
        if (item1.Mod != item2.Mod) {
            throw new Exception("mod not equal");
        }
    }

    public static ModInt operator +(ModInt item1, ModInt item2) {
        CheckNotEqualMod(item1, item2);
        long value = item1.Value + item2.Value;
        return new ModInt(value, item1.Mod);
    }

    public static ModInt operator *(ModInt item1, ModInt item2) {
        CheckNotEqualMod(item1, item2);
        long value = Math.BigMul(item1.Value, item2.Value);
        return new ModInt(value, item1.Mod);
    }

    public static ModInt operator -(ModInt item1, ModInt item2) {
        CheckNotEqualMod(item1, item2);
        long value = item1.Value - item2.Value;
        if (value < 0) {
            value += item1.Mod;
        }
        return new ModInt(value, item1.Mod);
    }

    public static ModInt operator +(ModInt item1, int item2) {
        return item1 + new ModInt(item2, item1.Mod);
    }

    public static ModInt operator *(ModInt item1, int item2) {
        return item1 * new ModInt(item2, item1.Mod);
    }

    public static ModInt operator -(ModInt item1, int item2) {
        return item1 - new ModInt(item2, item1.Mod);
    }


    public override int GetHashCode() {
        return this.Value;
    }

    public override bool Equals(object obj) {
        if (obj == null || this.GetType() != obj.GetType()) {
            return false;
        }

        var modIntObj = (ModInt)obj;
        return modIntObj.Value == this.Value;
    }

    public static bool operator ==(ModInt item1, ModInt item2) {
        return item1.Value == item2.Value;
    }

    public static bool operator !=(ModInt item1, ModInt item2) {
        return !(item1 == item2);
    }

    public static bool operator ==(ModInt item1, int item2) {
        return item1.Value == item2;
    }

    public static bool operator !=(ModInt item1, int item2) {
        return !(item1.Value == item2);
    }

    public static bool operator >=(ModInt item1, ModInt item2) {
        return item1.Value >= item2.Value;
    }

    public static bool operator <=(ModInt item1, ModInt item2) {
        return item1.Value <= item2.Value;
    }

    public static bool operator >=(ModInt item1, int item2) {
        return item1.Value >= item2;
    }

    public static bool operator <=(ModInt item1, int item2) {
        return item1.Value <= item2;
    }

    public static bool operator >(ModInt item1, ModInt item2) {
        return item1.Value > item2.Value;
    }

    public static bool operator <(ModInt item1, ModInt item2) {
        return item1.Value < item2.Value;
    }

    public static bool operator >(ModInt item1, int item2) {
        return item1.Value >= item2;
    }

    public static bool operator <(ModInt item1, int item2) {
        return item1.Value <= item2;
    }
}