using System;
 
using System.Collections.Generic;
 
using System.Linq;
 
using System.Reflection;
 
using System.Runtime.InteropServices;
 
using System.Security.Claims;
 
using System.Security.Cryptography.X509Certificates;
 
using System.Text;
 
using System.Threading.Tasks;
 
using System.Xml.Linq;
 
using Unit4.CollectionsLib;
 
 
 
namespace OpenS
 
{
 
    internal class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            // יצירת שרשרת חוליות (של מספרים שלמים) חדשה בעלת איבר אחד, איבר הבא נאל
 
            Node<int> node = new Node<int>(1);
 
            Console.WriteLine("Chain: " + node); // הדפסת השרשרת       
 
 
 
            node.SetValue(2); // עדכון ערך השרשרת
 
            Console.WriteLine("New Chain: " + node); // הדפסת השרשרת החדשה  
 
 
 
            // יצירת שרשרת חוליות (של מספרים שלמים) חדשה בעלת איבר אחד, איבר הבא נאל
 
            Node<int> chain = new Node<int>(1);
 
            Console.Write("New Chain: "); PrintChain(chain); // הדפסת (כל) השרשרת
 
 
 
            // יצירת שרשרת חוליות (של מספרים שלמים), איבר הבא נאל
 
            Node<int> chain1 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            Console.Write("New Chain: "); PrintChain(chain1); ; // הדפסת השרשרת
 
 
 
            // גישה לערכים
 
            Console.WriteLine("First Node Value: " + chain1.GetValue()); // קבלת הערך של האיבר הראשון
 
            Console.WriteLine("Second Node Value: " + chain1.GetNext().GetValue()); // קבלת הערך של האיבר השני
 
            Console.WriteLine("Third Node Value: " + chain1.GetNext().GetNext().GetValue()); // קבלת הערך של האיבר השלישי
 
            //...
 
 
 
            Node<int> chain2 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5))))); // יצירת שרשרת חדשה
 
            Console.Write("New Chain: "); PrintChainReverse(chain2); // הפעלת פונקציה שלוקחת שרשרת מקושרת ומחזירה את איברי השרשרת בסדר הפוך
 
 
 
            Node<int> chain3 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5))))); // יצירת שרשרת חדשה
 
            int size = SizeOfChain(chain3); // הפעלת פונקציה שלוקחת שרשרת ומחזירה את כמות האיברים בשרשרשת מקושרת
 
            Console.WriteLine("Size Of Chain: " + size); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain4 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int NodeValue1 = 1;
 
            int NodeValue2 = 0;
 
 
 
            bool IsNodeExists1 = IsNodeExists(chain4, NodeValue1); // הפעלת פונקציה שבודקת אם ערך ווליו שמתקבל קיים בשרשרת
 
            Console.WriteLine("Is The Value " + NodeValue1 + " Exist? " + IsNodeExists1);
 
 
 
            bool IsNodeExists2 = IsNodeExists(chain4, NodeValue2); // הפעלת פונקציה שבודקת אם ערך ווליו שמתקבל קיים בשרשרת
 
            Console.WriteLine("Is The Value " + NodeValue2 + " Exist? " + IsNodeExists2);
 
 
 
            Node<int> chain5 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            chain5 = RemoveFirst(chain5); // הפעלת פונקציה שלוקחת שרשרת ומסירה את האיבר הראשון בשרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain5); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain6 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            chain5 = RemoveLast(chain6); // הפעלת פונקציה שלוקחת שרשרת ומסירה את האיבר האחרון בשרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain6); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain7 = new Node<int>(1, new Node<int>(3, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int value1 = 3;
 
            bool IsNodeExists3 = IsNodeExists(chain7, value1); // בדיקה אם הערך שאנחנו רוצים להוציא מהשרשרת המקושרת בכלל קיים
 
 
 
            if (IsNodeExists3 == true) // אם הערך קיים
 
            {
 
                chain6 = RemoveByValue(chain6, value1); // הפעלת הפונקציה שמסירה איבר לפי ערך
 
                Console.Write("New Chain: "); PrintChain(chain6); // הדפסת השרשרת החדשה
 
            }
 
 
 
            Node<int> chain8 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int index = 3;
 
            chain8 = RemoveByIndex(chain8, index); // הפעלת הפונקציה שמירה איבר לפי אינדקס
 
            Console.Write("New Chain: "); PrintChain(chain8); // הדפסת השרשרת החדשה
 
 
 
            // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
            Node<int> chain9 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5))))); // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
            // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
            Node<int> chain10 = new Node<int>(5, new Node<int>(4, new Node<int>(3, new Node<int>(2, new Node<int>(1))))); // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
 
 
            bool isSorted1 = IsSortedAscending(chain7); // הפעלת הפונקציה שבודקת אם סדר האיברים עולה ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Ascending? " + isSorted1);
 
            bool isSorted2 = IsSortedAscending(chain8); // הפעלת הפונקציה שבודקת אם סדר האיברים עולה ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Ascending? " + isSorted2);
 
 
 
            bool isSorted3 = IsSortedDescending(chain9); // הפעלת הפונקציה שבודקת אם סדר האיברים יורד ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Descending? " + isSorted3);
 
            bool isSorted4 = IsSortedDescending(chain10); // הפעלת הפונקציה שבודקת אם סדר האיברים יורד ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Descending? " + isSorted4);
 
 
 
            Node<int> chain11 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            double average = Average(chain11); // הפעלת פונקציה שמחשבת את הממוצע ברשימה מקושרת ושמירתו במשתנה
 
            Console.WriteLine("The Average: " + average); // הדפסת הממוצע 
 
 
 
            Node<int> chain12 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int number = 6;
 
            chain12 = AddNodeStart(chain12, number); // עפעלת פונקציה שמוסיפה איבר בתחילת שרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain12); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain13 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int number1 = 0;
 
            AddNodeEnd(chain13, number1); // הפעלת פונקציה שמוסיפה איבר בסוף שרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain13); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain14 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int value = 10;
 
            int index1 = 5;
 
            chain14 = AddNodeAtIndex(chain14, index1, value); // הפעלת פונקציה שמוסיפה איבר בשרשרת מקושרת לפי אינדקס 
 
            Console.Write("New Chain: "); PrintChain(chain14); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain15 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5, new Node<int>(6))))));
 
            Node<int> chain16 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
 
 
            FindAndPrintMiddle(chain15); // הדפסת האיבר/ים האמצעי/ים
 
            FindAndPrintMiddle(chain16); // הדפסת האיבר/ים האמצעי/ים
 
 
 
            Node<int> chain17 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            Node<int> chain18 = new Node<int>(2, new Node<int>(2, new Node<int>(10, new Node<int>(4, new Node<int>(5)))));
 
 
 
            bool isBalanced1 = IsBalanced(chain17); // הפעלת פונקציה שבודקת אם ברשימה מקושרת מספר האיברים הגדולים מהממוצע שווה למספר האיברים הקטנים מהממוצע
 
            Console.WriteLine("Is the list balanced? " + isBalanced1);
 
 
 
            bool isBalanced2 = IsBalanced(chain18); // הפעלת פונקציה שבודקת אם ברשימה מקושרת מספר האיברים הגדולים מהממוצע שווה למספר האיברים הקטנים מהממוצע 
 
            Console.WriteLine("Is the list balanced? " + isBalanced2);
 
 
 
            Node<int> chain19 =
 
                new Node<int>(2,
 
                new Node<int>(2,
 
                new Node<int>(2,
 
                new Node<int>(2,
 
                new Node<int>(3,
 
                new Node<int>(2,
 
                new Node<int>(4)))))));
 
 
 
            int numToFind = 2;
 
            int sequenceCount = sequences(chain19, numToFind);
 
            Console.WriteLine($"Number of sequences for {numToFind}: {sequenceCount}");
 
 
 
            Node<int> chain20 = new Node<int>(2, new Node<int>(0, new Node<int>(3, new Node<int>(4, new Node<int>(5, new Node<int>(6))))));
 
            int minIndex = FindMinValueIndex(chain20); // הפעלת פונקציה שמוצאת את האינדקס של הערך הנמוך ביותר בשרשרת
 
            Console.WriteLine("The index of the minimum value is: " + minIndex); // הדפסת הערך
 
 
 
            Node<int> chain21 = new Node<int>(0, new Node<int>(1, new Node<int>(3, new Node<int>(4, new Node<int>(5, new Node<int>(6))))));
 
            int maxIndex = FindMaxValueIndex(chain21); // הפעלת פונקציה שמוצאת את האינדקס של הערך הנמוך ביותר בשרשרת
 
            Console.WriteLine("The index of the maximum value is: " + maxIndex); // הדפסת הערך
 
 
 
            Node<int> chain22 = new Node<int>(1, new Node<int>(2, new Node<int>(1, new Node<int>(4, new Node<int>(5)))));
 
            List<int> minIndexes = FindMinValueIndexes(chain22); // הפעלת פונקציה שמוצאת את האינדקס/ים של הערך/ים הנמוך/ים ביותר בשרשרת
 
            Console.WriteLine("The indexes of the minimum value is: " + string.Join(", ", minIndexes)); // הדפסת הערך
 
 
 
            Node<int> chain23 = new Node<int>(5, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            List<int> maxIndexes = FindMaxValueIndexes(chain23); // הפעלת פונקציה שמוצאת את האינדקס/ים של הערך/ים הנמוך/ים ביותר בשרשרת
 
            Console.WriteLine("The indexes of the maximum value is: " + string.Join(", ", maxIndexes)); // הדפסת הערך
 
 
 
            Node<int> chain24 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            List<int> secondMaxIndexes = FindSecondMaxValueIndex(chain24); // הפעלת הפונקציה
 
            Console.WriteLine("The index of the second maximum value is: " + string.Join(", ", secondMaxIndexes)); // הדפסת הערכים
 
 
 
            Node<int> chain25 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            List<int> secondMinIndexes = FindSecondMinValueIndex(chain25); // הפעלת הפונקציה
 
            Console.WriteLine("The index of the second minimum value is: " + string.Join(", ", secondMinIndexes)); // הדפסת הערכים
 
 
 
            Node<int> chain26 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(2, new Node<int>(1)))));
 
            Node<int> chain27 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            
 
            bool Palindrome1 = IsPalindrome(chain26); // הפעלת פונקציה שבודקת אם הרשימה היא פלינדרום
 
            Console.WriteLine("Is The Chain a Palindrome? " + Palindrome1);
 
            bool Palindrome2 = IsPalindrome(chain27); // הפעלת פונקציה שבודקת אם הרשימה היא פלינדרום
 
            Console.WriteLine("Is The Chain a Palindrome? " + Palindrome2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
        }
 
 
 
        // Node<int> current = chain; 
 
        // משתנה שמצביע על האיבר הנוכני ברשימה. בתחילת הלולאה הוא מצביע על ראש הרשימה.
 
 
 
 
 
        static void PrintChain(Node<int> chain) // פונקציה להדפסת כל האיברים ברשימה מקושרת 
 
        {
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים ברשימה עד לסופה
 
            {
 
                Console.Write(current.GetValue() + " ---> "); //הדפסת האיבר הנוכחי ברשימה
 
                current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
            }
 
 
 
            Console.WriteLine("Null!"); // לאחר סיום הפונקציה והדפסת כל האיברים, אין עוד איברים ולכן איבר הבא נאל
 
        }
 
 
 
        static void PrintChainReverse(Node<int> chain) // פונקציה להדפסת כל האיברים בסדר הפוך ברשימה מקושרת
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The chain is null. Nothing to print."); // הודעה מתאימה
 
                return; // יציאה מהפונקציה
 
            }
 
 
 
            List<int> values = new List<int>(); // רשימה זמנית לאחסון הערכים
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
 
 
            // איסוף כל הערכים בשרשרת
 
            while (current != null) // כל עוד השרשרת לא ריקה
 
            {
 
                values.Add(current.GetValue()); // מוסיף את הערך לרשימה של ווליוס
 
                current = current.GetNext(); // עבור לאיבר הבא
 
            }
 
 
 
            // הדפסת הערכים מהסוף להתחלה
 
            for (int i = values.Count - 1; i >= 0; i--)
 
            {
 
                Console.Write(values[i] + " ---> ");
 
            }
 
 
 
            Console.WriteLine("Null!"); // הגענו לאיבר האחרון
 
        }
 
 
 
        public static int SizeOfChain(Node<int> chain) // פונקציה שמחזירה את כמות האיברים ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return 0; // אין איברים
 
            }
 
 
 
            int size = 0; // אתחול הגודל
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
 
 
            while (current != null) // לולאה שרצה על כל איברי השרשרת
 
            {
 
                size++; // עלה את סכום האיברים
 
                current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
            }
 
 
 
            return size; // החזר את כמות האיברים
 
        }
 
 
 
        public static bool IsNodeExists(Node<int> chain, int value) // פונקציה שבודקת אם איבר קיים לפי ערך ווליו (שמתקבל בפרמטר) ברשימה מקושרת  
 
        {
 
            // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            Node<int> current = chain;
 
 
 
            // לולאה שרצה על כל האיברים ברשימה
 
            while (current != null)
 
            {
 
                // אם הערך של האיבר הנוכחי שווה לערך שחיפשנו
 
                if (current.GetValue() == value)
 
                {
 
                    return true; // מצאנו את הערך
 
                }
 
 
 
                // עוברים לאיבר הבא
 
                current = current.GetNext();
 
            }
 
 
 
            // אם יצאנו מהלולאה בלי למצוא את הערך, האיבר לא קיים
 
            return false;
 
        }
 
 
 
        public static Node<int> RemoveFirst(Node<int> chain) // פונקציה שמסירה את האיבר הראשון ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return null; // מקרה קיצון, אין איברים להסרה
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            return chain.GetNext(); // הסרת האיבר הראשון והחזרת הרשימה החדשה
 
        }
 
 
 
        public static Node<int> RemoveLast(Node<int> chain) // פונקציה שמסירה את האיבר האחרון ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return null; // מקרה קיצון, אין איבר להסרה
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
 
 
            while (current.GetNext().GetNext() != null) // לולאה שרצה עד לאיבר האחרון
 
            {
 
                current = current.GetNext(); // עבור לאיבר הבא 
 
            }
 
 
 
            current.SetNext(null); // הסרת האיבר האחרון
 
            return chain; // החזרת הרשימה החדשה
 
        }
 
 
 
        public static Node<int> RemoveByValue(Node<int> chain, int value) // פונקציה שמסירה את האיבר האחרון ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return null; // מקרה קיצון, אין איבר להסרה
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            Node<int> NewNode = new Node<int>(0); // יצירת שרשרת חדשה לאחסון השרשרת המקורית
 
            NewNode.SetNext(chain); // קישור לראש הרשימה
 
            Node<int> prev = NewNode; // משתנה לאחסון האיבר הקודם
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            bool flag = false; // משתנה בוליאני שאומר האם מצאנו את האיבר להסרה
 
 
 
            while (current != null) // לולאה שעוברת על כל הרשימה
 
            {
 
                if (current.GetValue() == value) // אם מצאנו את האיבר להסרה
 
                {
 
                    prev.SetNext(current.GetNext()); // קישור האיבר הקודם לאיבר הבא של האיבר הנוכחי
 
                    flag = true; // עדכון המשתנה שמעיד שמצאנו את האיבר
 
                }
 
 
 
                else // אם לא מצאנו את האיבר הנוכחי
 
                {
 
                    prev = current; // עדכון האיבר הקודם לאיבר הנוכחי
 
                }
 
 
 
                current = current.GetNext(); // עבור לאיבר הבא
 
            }
 
 
 
            if (!flag) // אם לא מצאנו את האיבר להסרה
 
            {
 
                Console.WriteLine($"Value {value} does not exist!"); // הערך לא קיים בשרשרת
 
                return null; // מקרה קיצון, צא מהפונקציה
 
            }
 
 
 
            return NewNode.GetNext(); // החזר את השרשרת החדשה
 
        }
 
 
 
        public static Node<int> RemoveByIndex(Node<int> chain, int index) // פונקציה שמסירה את איבר לפי אינדקס שמתקבל בפרמטר ברשימה מקושרת 
 
        {
 
            if (chain == null || index < 0) // אם הרשימה ריקה או שהאינדקס שלילי
 
            {
 
                return null; // מקרה קיצון, אין איבר להעיף
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            Node<int> prev = null; // מצביע על הצומת הקודם
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            int currentIndex = 0; // מכיל את האינדקס הנוכחי שאנחנו נמצאים בו ברשימה
 
 
 
            while (current != null) // לולאה שרצה על כל האיברים
 
            {
 
                if (currentIndex == index) // אם מצאנו את האינדקס
 
                {
 
                    if (prev == null)  // אם האיבר להסרה הוא האיבר הראשון
 
                    {
 
                        chain = current.GetNext(); // עדכון הראש של הרשימה לאיבר הבא
 
                    }
 
 
 
                    else // אם האיבר להסרה הוא לא האיבר הראשון
 
                    {
 
                        prev.SetNext(current.GetNext()); // קישור האיבר הקודם לאיבר הבא של האיבר הנוכחי
 
                    }
 
 
 
                }
 
 
 
                prev = current; // האיבר הקודם עובר להיות האיבר הנוכחי
 
                current = current.GetNext(); // עבור לאיבר הבא
 
                currentIndex++; // עברנו האינדקס הנוכחי
 
            }
 
 
 
            if (currentIndex <= index) // אם הגענו לסוף הרשימה מבלי למצוא את האינדקס
 
            {
 
                Console.WriteLine($"Index {index} does not exist!"); // האינדקס לא קיים
 
                return null; // מקרה קיצון, צא מהפונקציה
 
            }
 
 
 
            return chain; // החזרת הרשימה החדשה
 
        }
 
 
 
        public static bool IsSortedAscending(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת ממוינת בסדר עולה
 
        {
 
            if (chain == null || chain.GetNext() == null) // בדוק אם השרשרת ריקה או שקיים רק איבר אחד
 
            {
 
                return false; // אין סדר עולה
 
            }
 
 
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            while (current.GetNext() != null) // לולאה שעוברת על כל האיברים
 
            {
 
                if (current.GetValue() >= current.GetNext().GetValue()) // אם הערך הנוכחי גדול מהערך הבא
 
                {
 
                    return false; // הרשימה לא מסודרת
 
                }
 
 
 
                current = current.GetNext(); // עוברים לאיבר הבא
 
            }
 
 
 
            return true; // אם עברנו את כל הבדיקות, הרשימה מסודרת בסדר עולה
 
        }
 
 
 
        public static bool IsSortedDescending(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת ממוינת בסדר יורד
 
        {
 
            if (chain == null || chain.GetNext() == null) // בדוק אם השרשרת ריקה או שקיים רק איבר אחד
 
            {
 
                return false; // אין סדר עולה
 
            }
 
 
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            while (current.GetNext() != null) // לולאה שעוברת על כל האיברים ברשימה עד הסוף
 
            {
 
                if (current.GetValue() <= current.GetNext().GetValue()) // אם הערך הנוכחי קטן או שווה לערך הבא
 
                {
 
                    return false; // הרשימה לא בסדר יורד
 
                }
 
 
 
                current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
            }
 
 
 
            return true; // אם עברנו את כל הבדיקות, הרשימה מסודרת בסדר יורד
 
        }
 
 
 
        public static double Average(Node<int> chain) // פונקציה שמדפיסה את ממוצע ערך האיברים ברשימה מקושרת  
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return 0; // ממוצע אפס
 
            }
 
 
 
            int sum = 0; // משתנה לשמירת סכום כל הערכים ברשימה
 
            int count = 0; // משתנה לספירת מספר האיברים ברשימה
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים ברשימה עד שהיא מגיעה לסוף
 
            {
 
                sum += current.GetValue(); // מוסיף את הערך של האיבר הנוכחי לסכום
 
                count++; // מגדיל את ספירת האיברים
 
                current = current.GetNext(); // מעביר את המצביע לאיבר הבא ברשימה
 
            }
 
 
 
            return (double)sum / count; // החזר את הממוצע
 
        }
 
 
 
        public static Node<int> AddNodeStart(Node<int> chain, int data) // פונקציה שמוסיפה איבר בתחילת רשימה מקושרת   
 
        {
 
            // יצירת איבר חדש
 
            Node<int> newNode = new Node<int>(data);
 
 
 
            // הגדר את האיבר הבא לשרשרת המקורית 
 
            newNode.SetNext(chain);
 
 
 
            // החזר את הרשימה החדשה לאחר הוספת האיבר 
 
            return newNode;
 
        }
 
 
 
        public static void AddNodeEnd(Node<int> chain, int value) // פונקציה שמוסיפה איבר בסוף רשימה מקושרת  
 
        {
 
            // יצירת איבר חדש עם הערך שקיבלנו מהפרמטר
 
            Node<int> newNode = new Node<int>(value);
 
 
 
            // בדוק אם הרשימה ריקה. אם כן, אין איבר להוספה
 
            if (chain == null) return;
 
 
 
            else
 
            {
 
                Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
                while (current.GetNext() != null) // לולאה שעוברת על כל האיברים ברשימה
 
                {
 
                    current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
                }
 
 
 
                current.SetNext(newNode); // חיבור האיבר החדש לסוף הרשימה
 
            }
 
        }
 
 
 
        public static Node<int> AddNodeAtIndex(Node<int> chain, int index, int value) // פונקציה שמוסיפה איבר לפי אינדקס (שמתקבל בפרמטר) ברשימה מקושרת  
 
        {
 
            // יצירת איבר חדש עם הערך שקיבלנו מהפרמטר
 
            Node<int> newNode = new Node<int>(value);
 
 
 
            // בדוק אם הרשימה ריקה או אם האינדקס אינו תקין אם כן צא מהפונקציה
 
            if (chain == null || index < 0)
 
            {
 
                Console.WriteLine("Chain Is Empty Or Index Is");
 
                return null;
 
            }
 
 
 
            // אם האינדקס הוא 0, הוסף את האיבר החדש בתחילת הרשימה
 
            if (index == 0)
 
            {
 
                // הגדר את האיבר הבא לשרשרת המקורית 
 
                newNode.SetNext(chain);
 
 
 
                // החזר את הרשימה החדשה לאחר הוספת האיבר 
 
                return newNode;
 
            }
 
 
 
            // מציאת האיבר לפני המקום שבו רוצים להוסיף
 
            Node<int> current = chain;  // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
            int currentIndex = 0; // משתנה לאחסון האינדקס הנוכחי
 
 
 
            while (current != null && currentIndex < index - 1) // לולאה לחיפוש האיבר המבוקש לפי האינדקס בפרמטר
 
            {
 
                current = current.GetNext(); // עבור לאיבר הבא
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            // אם הגענו לסוף הרשימה, האינדקס לא קיים
 
            if (current == null)
 
            {
 
                Console.WriteLine("Nonexistent Index!"); // הדפסת הודעה מתאימה
 
                return null; // מקרה קיצון, יציאה מהפונקציה
 
            }
 
 
 
            // חיבור האיבר החדש לרשימה
 
            newNode.SetNext(current.GetNext()); // קישור האיבר החדש לאיבר הבא
 
            current.SetNext(newNode); // קישור האיבר הקודם לאיבר החדש
 
            return chain; // החזרת הראשימה החדשה
 
        }
 
 
 
        public static void FindAndPrintMiddle(Node<int> chain) // פונקציה שמוצאת את האיברים האמצעיים ברשימה מקושרת ומדפיסה אותם
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return; // יציאה מהפונקציה
 
            }
 
 
 
            Node<int> slow = chain; // משתנה עזר ראשון שמצביע לאיבר הראשון ברשימה
 
            Node<int> fast = chain; // משתנה עזר שני שמצביע לאיבר הראשון ברשימה
 
            Node<int> prevSlow = null; // משתנה לאחסון האיבר הקודם של סלואו
 
 
 
            while (fast != null && fast.GetNext() != null) // לולאה שרצה על כל האיברים
 
            {
 
                prevSlow = slow; // עדכון האיבר הקודם להיות האיבר הנוכחי
 
                slow = slow.GetNext(); // האיבר הנוכחי הראשון עובר לאיבר הבא
 
                fast = fast.GetNext().GetNext(); // האיבר הנוכחי השני עובר שני איברים קדימה
 
            }
 
 
 
            if (fast == null) // מספר זוגי של איברים
 
            {
 
                Console.WriteLine($"The Middle Nodes: {prevSlow.GetValue()} and {slow.GetValue()}");
 
            }
 
 
 
            else // מספר אי זוגי של איברים
 
            {
 
                Console.WriteLine($"The Middle Node: {slow.GetValue()}");
 
            }
 
        }
 
 
 
        public static int GetValueByIndex(Node<int> chain, int index) // פונקציה  שעוברת על כל האיברים בשרשרת ומחזירה את הערך של האיבר כאשר היא מגיעה לאינדקס המבוקש
 
        {
 
            int currentIndex = 0; // מייצג את האינדקס הנוכחי בשרשרת
 
            Node<int> currentNode = chain; // משתנה עזר לשמירת האיבר הנוכחי
 
 
 
            // לולאה שרצה על האיברים כל עוד לא הגענו לסוף השרשרת
 
            while (currentNode != null)
 
            {
 
                // בודק אם הגענו לאינדקס המבוקש
 
                if (currentIndex == index)
 
                {
 
                    return currentNode.GetValue(); // מחזיר את הערך אם הגענו לאינדקס המבוקש
 
                }
 
 
 
                // מתקדם לאיבר הבא ומגדיל את האינדקס הנוכחי באחד
 
                currentNode = currentNode.GetNext();
 
                currentIndex++;
 
            }
 
 
 
            return -1; // מחזיר -1 אם לא נמצא האיבר באינדקס המבוקש
 
        }
 
 
 
        public static int GetIndexByValue(Node<int> chain, int value) // פונקציה לקבלת אינדקס בעזרת ערך מסוים ברשימה מקושרת
 
        {
 
            int currentIndex = 0; // משתנה לאחסון האינדקס הנוכחי
 
            Node<int> currentNode = chain; // מצביע לאיבר הנוכחי ברשימה
 
 
 
            while (currentNode != null) // לולאה שעוברת על כל האיברים ברשימה
 
            {
 
                if (currentNode.GetValue() == value) // בדיקה אם הערך של הנוד הנוכחי תואם לערך המבוקש
 
                {
 
                    return currentIndex; // מחזיר את האינדקס אם הערך נמצא
 
                }
 
 
 
                currentNode = currentNode.GetNext(); // מעבר לאיבר הבא הרשימה 
 
                currentIndex++; // הגדלת האינקס
 
            }
 
 
 
            return -1; // החזר -1 אם הערך לא נמצא
 
        }
 
 
 
        public static bool IsBalanced(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת היא גם "רשימה מאוזנת". רשימה מאוזנת היא רשימה שמספר האיברים הגדולים מהממוצע שווה למספר האיברים הקטנים מהממוצע.
 
        {
 
            // אם הרשימה ריקה, היא נחשבת מאוזנת
 
            if (chain == null) return true;
 
 
 
            int sum = 0; // משתנה לשמירת סכום הערכים
 
            int count = 0; // משתנה לספירת האיברים
 
 
 
            Node<int> current = chain;  // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            while (current != null) // לולאה שרצה על כל האיברים
 
            {
 
                sum += current.GetValue(); // הוספת הערך לסכום
 
                count++; // העלאת מונה האיברים
 
                current = current.GetNext(); // מעבר לאיבר הבא
 
            }
 
 
 
            // חישוב הממוצע
 
            double average = (double)sum / count;
 
 
 
            int greaterCount = 0; // משתנה לספירת איברים הגדולים מהממוצע
 
            int lesserCount = 0; // משתנה לספירת איברים הקטנים מהממוצע
 
 
 
            current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            // ספירת האיברים הגדולים והקטנים מהממוצע
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים
 
            {
 
                if (current.GetValue() > average) // אם הערך גדול מהממוצע
 
                {
 
                    greaterCount++; // ספירת איבר גדול מהממוצע
 
                }
 
 
 
                else if (current.GetValue() < average) // אם הערך קטן מהממוצע
 
                {
 
                    lesserCount++; // ספירת איבר קטן מהממוצע
 
                }
 
                current = current.GetNext(); // מעבר לאיבר הבא ברשימה
 
            }
 
 
 
            return greaterCount == lesserCount; // החזרת התשובה האם הרשימה היא מאוזנת
 
        }
 
 
 
        public static int sequences(Node<int> chain, int num) // פונקציה שבודקת את מספר הרצפים שיש ברשימה מקושרת עבור מספר מסוים
 
        {
 
            int sequences = 0; // סוכם הרצפים
 
            Node<int> pos = chain; // משתנה עזר למיקום נוכחי ברשימה
 
            bool inSequence = false; // בדיקה אם הרצף ממשיך
 
            int count = 0; // מונה למופעים רצופים
 
 
 
            // לולאה שרצה כל עוד לא הגענו לסוף הרשימה
 
            while (pos != null)
 
            {
 
                // בודק אם הערך של הצומת הנוכחי שווה למספר שאנחנו מחפשים
 
                if (pos.GetValue() == num)
 
                {
 
                    count++; // מוסיף למונה
 
                    inSequence = true; // הרצף קיים
 
                }
 
 
 
                else
 
                {
 
                    if (inSequence && count >= 2) // אם סיימנו רצף עם 2 מופעים או יותר
 
                    {
 
                        sequences++; // מוסיפים לספירה
 
                    }
 
 
 
                    inSequence = false; // הרצף הפסיק
 
                    count = 0; // מאפס את המונה
 
                }
 
 
 
                // עובר לאיבר הבא ברשימה
 
                pos = pos.GetNext();
 
            }
 
 
 
            // בודק במקרה שהרצף נגמר בסוף הרשימה
 
            if (inSequence && count >= 2)
 
            {
 
                sequences++;
 
            }
 
 
 
            // מחזיר את מספר הרצפים של המספר המבוקש
 
            return sequences;
 
        }
 
 
 
        public static int FindMinValueIndex(Node<int> chain) // פונצקיה שמקבלת שרשרת ומחזירה את האינדקס של האינדקס של הערך הנמוך ביותר בשרשרת מקושרת
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return -1; // יציאה מהפונקציה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר לשמירת השרשרת המקורית
 
            int minValue = pos.GetValue(); // אתחול הערך המינימלי לערך החוליה הראשונה
 
            int minIndex = 0; // אינדקס המינימום מתחיל מאפס
 
            int currentIndex = 0; // מונה אינדקס נוכחי
 
 
 
            // לולאה שעוברת על כל החוליות ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() < minValue) // עם הערך הנוכחי קטן מהערך המינימלי הקודם
 
                {
 
                    minValue = pos.GetValue(); // עדכון הערך המינימלי
 
                    minIndex = currentIndex; // עדכון האינדקס למיקום הנמוך ביותר
 
                }
 
 
 
                pos = pos.GetNext(); // מעבר לחוליה הבאה
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return minIndex; // החזרת האינדקס של הערך הנמוך ביותר
 
        }
 
 
 
        public static int FindMaxValueIndex(Node<int> chain) // פונקציה שמקבלת שרשרת ומחזירה את האינדקס של הערך הגבוה ביותר בשרשרת המקושרת
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return -1; // החזרת -1 במקרה של שרשרת ריקה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר לשמירת השרשרת המקורית
 
            int maxValue = pos.GetValue(); // אתחול הערך המקסימלי לערך של החוליה הראשונה
 
            int maxIndex = 0; // אינדקס המקסימום מתחיל מאפס
 
            int currentIndex = 0; // מונה אינדקס נוכחי
 
 
 
            // לולאה שעוברת על כל החוליות ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() > maxValue) // אם הערך הנוכחי גדול מהערך המקסימלי הקודם
 
                {
 
                    maxValue = pos.GetValue(); // עדכון הערך המקסימלי
 
                    maxIndex = currentIndex; // עדכון האינדקס למיקום הגבוה ביותר
 
                }
 
 
 
                pos = pos.GetNext(); // מעבר לחוליה הבאה
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return maxIndex; // החזרת האינדקס של הערך הגבוה ביותר
 
        }
 
 
 
        public static List<int> FindMinValueIndexes(Node<int> chain) // פונקציה שמקבלת שרשרת ומחזירה את האינדקס/ים עם הערך/ים הכי נמוך/ים
 
        {
 
            if (chain == null) // אם הרשימה ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return null; // מקרה קיצון, יציאה מהפונקציה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר שמחזיק את השרשרת המקורית
 
            int minValue = pos.GetValue(); // אתחול ערך מינימלי עם הערך של האיבר הראשון
 
            List<int> minIndexes = new List<int>(); // רשימה להחזיק את האינדקסים של הערך/ים המינימלי/ם
 
            int currentIndex = 0; // מונה אינדקסים נוכחי
 
 
 
            // לולאה שעוברת על כל הצמתים ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() < minValue) // אם הערך הנוכחי קטן מהערך המינימלי הקודם
 
                {
 
                    minValue = pos.GetValue(); // עדכון הערך המינימלי
 
                    minIndexes.Clear(); // ניקוי אינדקסים קודמים
 
                    minIndexes.Add(currentIndex); // הוספת האינדקס המינימלי החדש
 
                }
 
 
 
                else if (pos.GetValue() == minValue) // אם הערך הנוכחי שווה לערך המינימלי הנוכחי
 
                {
 
                    minIndexes.Add(currentIndex); // הוספת אינדקס זה לרשימת האינדקסים המינימליים
 
                }
 
 
 
                pos = pos.GetNext(); // // מעבר לאיבר הבא
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return minIndexes; // החזרת האינדקסים של הערכים המינימלים
 
        }
 
 
 
        public static List<int> FindMaxValueIndexes(Node<int> chain) // פונקציה שמקבלת שרשרת ומחזירה את האינדקסים עם הערך/ים הכי גבוה/ים בשרשרת מקושרת
 
        {
 
            if (chain == null) // אם הרשימה ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return null; // מקרה קיצון, יציאה מהפונקציה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר לשמירת השרשרת המקורית
 
            int maxValue = pos.GetValue(); // אתחול ערך מקסימלי עם הערך של האיבר הראשון
 
            List<int> maxIndexes = new List<int>(); // רשימה להחזיק את האינדקסים של הערך/ים המקסימלי/ם
 
            int currentIndex = 0; // מונה אינדקסים נוכחי
 
 
 
            // לולאה שעוברת על כל הצמתים ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() > maxValue) // אם הערך הנוכחי גדול מהערך המקסימלי הקודם
 
                {
 
                    maxValue = pos.GetValue(); // עדכון הערך המקסימלי
 
                    maxIndexes.Clear(); // ניקוי אינדקסים קודמים
 
                    maxIndexes.Add(currentIndex); // הוספת האינדקס המקסימלי החדש
 
                }
 
                else if (pos.GetValue() == maxValue) // אם הערך הנוכחי שווה לערך המקסימלי הנוכחי
 
                {
 
                    maxIndexes.Add(currentIndex); // הוספת אינדקס זה לרשימת האינדקסים המקסימליים
 
                }
 
 
 
                pos = pos.GetNext(); // מעבר לאיבר הבא
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return maxIndexes; // החזרת האינדקסים של הערכים המקסימליים
 
        }
 
 
 
        public static List<int> FindSecondMaxValueIndex(Node<int> chain) // פונקציה שמקבלת שרשרת 
 
        {
 
            if (chain == null) return new List<int>(); // אם הרשימה ריקה, מחזירים רשימה ריקה
 
 
 
            int max = int.MinValue;
 
            int secondMax = int.MinValue;
 
            List<int> secondMaxIndexes = new List<int>();
 
            int index = 0;
 
 
 
            // סיבוב על כל האלמנטים בשרשרת
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                // מעדכנים את הערכים המקסימליים
 
                if (current.GetValue() > max)
 
                {
 
                    secondMax = max; // הערך הקודם הופך לערך השני הכי גבוה
 
                    max = current.GetValue(); // מעדכנים את הערך המקסימלי
 
                }
 
 
 
                else if (current.GetValue() > secondMax && current.GetValue() < max)
 
                {
 
                    secondMax = current.GetValue(); // מעדכנים את הערך השני הכי גבוה
 
                }
 
 
 
                index++;
 
            }
 
 
 
            // מחפשים את כל האינדקסים של הערך השני הכי גבוה
 
            index = 0; // מאפסים את האינדקס
 
 
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                if (current.GetValue() == secondMax)
 
                {
 
                    secondMaxIndexes.Add(index); // מוסיפים את האינדקס לרשימה
 
                }
 
 
 
                index++;
 
            }
 
 
 
            return secondMaxIndexes; // מחזירים את הרשימה של אינדקסים
 
        }
 
 
 
        public static List<int> FindSecondMinValueIndex(Node<int> chain) // פונקציה שמקבלת שרשרת
 
        {
 
            if (chain == null) return new List<int>(); // אם הרשימה ריקה, מחזירים רשימה ריקה
 
 
 
            int min = int.MaxValue;
 
            int secondMin = int.MaxValue;
 
            List<int> secondMinIndexes = new List<int>();
 
            int index = 0;
 
 
 
            // סיבוב על כל האלמנטים בשרשרת
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                // מעדכנים את הערכים המינימליים
 
                if (current.GetValue() < min)
 
                {
 
                    secondMin = min; // הערך הקודם הופך לערך השני הכי נמוך
 
                    min = current.GetValue(); // מעדכנים את הערך המינימלי
 
                }
 
                else if (current.GetValue() < secondMin && current.GetValue() > min)
 
                {
 
                    secondMin = current.GetValue(); // מעדכנים את הערך השני הכי נמוך
 
                }
 
 
 
                index++;
 
            }
 
 
 
            // מחפשים את כל האינדקסים של הערך השני הכי נמוך
 
            index = 0; // מאפסים את האינדקס
 
 
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                if (current.GetValue() == secondMin)
 
                {
 
                    secondMinIndexes.Add(index); // מוסיפים את האינדקס לרשימה
 
                }
 
 
 
                index++;
 
            }
 
 
 
            return secondMinIndexes; // מחזירים את הרשימה של אינדקסים
 
        }
 
 
 
        public static bool IsPalindrome(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת היא פלינדרום
 
        {
 
            // אם הרשימה ריקה או כוללת איבר אחד, היא נחשבת פלינדרום
 
            if (chain == null || chain.GetNext() == null) return true;
 
 
 
            // שלב 1: העתקת הערכים לרשימה כדי שניתן יהיה לקרוא אחורה
 
            List<int> values = new List<int>();
 
            Node<int> current = chain; // משתנה עזר לשמירת השרשרת המקורית
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים ומוסיפה אותם לרשימה
 
            {
 
                values.Add(current.GetValue());
 
                current = current.GetNext();
 
            }
 
 
 
            // שלב 2: בדיקת סימטריה
 
            int left = 0; // התחלה של הרשימה
 
            int right = values.Count - 1; // סוף של הרשימה
 
 
 
            while (left < right) // לולאה שממשיכה כל עוד יש איברים משני הצדדים
 
            {
 
                if (values[left] != values[right]) // אם הערכים אינם שווים
 
                {
 
                    return false; // השרשרת אינה פלינדרום
 
                }
 
                left++;
 
                right--;
 
            }
 
 
 
            return true; // אם כל הערכים היו שווים, הרשימה היא פלינדרום
 
        }
 
 
 
    }
 
}