기본 알고리즘 01

버블정렬

기본 개념은 인접한 레코드의 키 코드를 비교하여 이전 레코드의 키 코드가 이후 레코드의 키 코드보다 크면 교환하고 그렇지 않으면 교환하지 않는 것입니다.

bool swapped = true;
do{
	swapped = false;
	for(int i =0;i<sortArray.Length -1;i++){
		if(sortArray[i]>sortArray[i+1]){
			int temp= sortArray[i];
			sortArray[i]=sortArray[i+1];
			sortArray[i+1]=temp;
			swapped = true;
		}
	}
}while(swapped);

 

 분열시켜 정복하라

주식 매입 문제를 나누어 정복하세요

1. 먼저 주식의 일일 가격 변동 배열을 계산합니다.

2. 가운데 숫자를 찾습니다. 중위수 이전의 숫자를 최대 소득값으로 계산하고, 중위수 뒤의 숫자를 최대 입력값으로 계산하여 이 둘을 합산하여 총 소득값을 계산합니다.

3. 3개를 비교하여 매수일과 매도일을 반환합니다.

    class Program
    {
        //最大子数组的结构体
        struct Income
        {
            public int startIndex;
            public int endIndex;
            public int total;
        }
        static void Main(string[] args)
        {
            // 股票每天的价格
            int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
            // 价格波动的数组
            int[] priceFluctuation = new int[priceArray.Length - 1];
            for (int i = 1; i < priceArray.Length; i++)
            {
                priceFluctuation[i - 1] = priceArray[i] - priceArray[i - 1];
            }
            Income subArray = GetMaxSubArray(0, priceFluctuation.Length - 1, priceFluctuation);
            Console.WriteLine(subArray.startIndex);
            Console.WriteLine(subArray.endIndex);
            Console.WriteLine("我们在第" + subArray.startIndex + "天买入, 在第" + (subArray.endIndex + 1) + "天卖出");
            Console.ReadKey();
        }

        static Income GetMaxSubArray(int low, int high, int[] array)//这个方法是用来取得array 这个数组 从low到high之间的最大子数组
        {

            if (low == high)
            {
                Income subarray;
                subarray.startIndex = low;
                subarray.endIndex = high;
                subarray.total = array[low];
                return subarray;
            }
            //取中间的索引,划分高低区间  低区间 [low,mid]  高区间[mid=1,high]
            int mid = (low + high) / 2;
            // 低区间 [low,mid] 的最大收入
            Income income1 = GetMaxSubArray(low, mid, array);
            // 高区间[mid=1,high] 的最大收入
            Income income2 = GetMaxSubArray(mid + 1, high, array);

            //从mid往前遍历,找到最大子收入的开始索引
            int totalIncome1 = array[mid] ;
            int startIndex = mid;
            int totalIncome1Temp = 0;
            for (int i = mid; i >= low; i--)
            {
                totalIncome1Temp += array[i];
                if (totalIncome1Temp > totalIncome1)
                {
                    totalIncome1 = totalIncome1Temp;
                    startIndex = i;
                }
            }
            //从mid+1往后遍历,找到最大收入的索引
            int totalIncom2 = array[mid + 1];
            int endIndex = mid + 1;
            totalIncome1Temp = 0;
            for (int j = mid + 1; j <= high; j++)
            {
                totalIncome1Temp += array[j];
                if (totalIncome1Temp > totalIncom2)
                {
                    totalIncom2 = totalIncome1Temp;
                    endIndex = j;
                }
            }
            Income subArray3;
            subArray3.startIndex = startIndex;
            subArray3.endIndex = endIndex;
            subArray3.total = totalIncome1 + totalIncom2;
            if (income1.total >= income2.total && income1.total >= subArray3.total)
            {
                return income1;
            }
            else if (income2.total >= income1.total && income2.total >= subArray3.total)
            {
                return income2;
            }
            else
            {
                return subArray3;
            }
        }
    }

동적 프로그래밍

배낭 문제

bagCapcity kg 및 itemCount 품목의 용량을 갖춘 배낭입니다.

무게는 무게[1] 무게[2] ... 무게[i](kg)입니다.

값은 가격[1] p[2] ... p[i](위안)입니다.

배낭의 전체 가치를 극대화하기 위해 배낭에 어떤 품목을 넣을 수 있습니까? 최대값은 얼마입니까?

m(kg) 용량의 배낭에 넣은 i개 물체의 최대값 MaxValue[i,m]

각 항목 i에는 배낭에 넣을 것인지, 넣지 않을 것인지의 두 가지 옵션만 있으므로 이 문제를 0-1 배낭 문제라고 합니다.

1. 넣은 물건이 배낭 용량을 초과하는 경우 폐기하십시오.

2. 배낭에 넣은 값을 값으로 계산하고, 배낭에 넣지 않은 값을 값으로 계산하여 비교하여 배낭에 넣은 값이 크면 넣고, 작으면 넣습니다. , 넣지 마세요. 그런 다음 분할 정복 방법을 사용하여 차례로 찾아내고, 매번 얻은 결과를 2차원 배열로 저장합니다. 두 개의 아래 첨자가 있는 데이터 그룹

2차원 배열의 선언은 다음과 같습니다.

int[,] 배열=새로운 int[2,3]{ {1,2,3},{1,2,3}}

다음 알고리즘은 이렇게 이해될 수 있습니다: 배낭 m, i개 항목 넣기, 최대값

배낭 용량이 1일 때 어떤 아이템의 가치가 가장 높을까요? 적어보세요. 배낭 용량이 2일 때 어떤 아이템의 가치가 가장 높나요? 또한 가장 큰 가치를 지닌 아이템을 적어보세요. 마지막으로 배낭으로 진화합니다. m의 용량과 동시에 어떤 항목이 가장 큰 가치를 갖습니까?

    class Program
    {
        static void Main(string[] args)
        {
            int bagCapcity;
            int[] weights = { 0, 3, 4, 5 };
            int[] prices = { 0, 4, 5, 6 };
            // 10背包容量,商店中的i个物品
            Console.WriteLine(BottomUp(10, 3, weights, prices));
            Console.WriteLine(BottomUp(3, 3, weights, prices));
            Console.WriteLine(BottomUp(4, 3, weights, prices));
            Console.WriteLine(BottomUp(5, 3, weights, prices));
            Console.WriteLine(BottomUp(7, 3, weights, prices));

            Console.ReadKey();
        }
        // 存的值是背包的最大价值,下标1背包的容量,下标2是放的物品数
        public static int[,] result = new int[11, 4];//11行,4列共44个元素
        public static int BottomUp(int bagCapcity,int storeNum,int[] weights,int[] prices)
        {
            if (result[bagCapcity, storeNum] != 0) 
            {
                return result[bagCapcity, storeNum];
            }
            // m代表背包重量,n表示放入的第n个物品
            for (int bagm = 1; bagm < bagCapcity + 1; bagm++)
            {
                for (int storeIndex = 1; storeIndex < storeNum + 1; storeIndex++)
                {
                    if (result[bagm, storeIndex] != 0) 
                    {
                        continue;
                    }
                    // 物品重量大于背包重量,n物品不能放入背包
                    if (weights[storeIndex] > bagm)
                    {
                        result[bagm, storeIndex] = result[bagm, storeIndex - 1];
                    }
                    else
                    {
                        // 放入背包的价值
                        int maxValue1 = result[bagm - weights[storeIndex], storeIndex - 1] + prices[storeIndex];
                        // 不放入背包的价值
                        int maxValue2 = result[bagm, storeIndex - 1];
                        // 哪个价值大,代表背包m,n个物品的价值最大
                        if (maxValue1 > maxValue2)
                        {
                            result[bagm, storeIndex] = maxValue1;
                        }
                        else
                        {
                            result[bagm, storeIndex] = maxValue2;
                        }
                    }
                }
            }
            return result[bagCapcity, storeNum];
        }
    }

철근 절단 문제

    class Program
    {
        static void Main(string[] args)
        {
            //int n = 5;//我们要切割售卖的钢条的长度
            int[] result = new int[11];
            int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//索引代表 钢条的长度,值代表价格
            Console.WriteLine(UpDown(0, p, result));
            Console.WriteLine(UpDown(1, p, result));
            Console.WriteLine(UpDown(2, p, result));
            Console.WriteLine(UpDown(3, p, result));
            Console.WriteLine(UpDown(4, p, result));
            Console.WriteLine(UpDown(5, p, result));
            Console.WriteLine(UpDown(6, p, result));
            Console.WriteLine(UpDown(7, p, result));
            Console.WriteLine(UpDown(8, p, result));
            Console.WriteLine(UpDown(9, p, result));
            Console.WriteLine(UpDown(10, p, result));
            Console.ReadKey();
        }
        //带备忘的自顶向下法
        public static int UpDown(int n, int[] p,int[] result)//求得长度为n的最大收益
        {
            if (n == 0) return 0;
            if (result[n] != 0)
            {
                return result[n];
            }
            int tempMaxPrice = 0;
            for (int i = 1; i < n + 1; i++)
            {
                int maxPrice = p[i] + UpDown(n - i, p, result);
                if (maxPrice > tempMaxPrice)
                {
                    tempMaxPrice = maxPrice;
                }
            }
            result[n] = tempMaxPrice;
            return tempMaxPrice;
        }
    }

그리디 알고리즘

회의 일정 충돌 문제

회의 활동의 일정 충돌 문제를 해결하고 하루에 가장 많이 예정된 활동의 지수를 알아보세요.

    class Program
    {
        static void Main(string[] args)
        {

            List<int> list = ActivitySelection(1, 11, 0, 24);
            foreach (int temp in list)
            {
                Console.WriteLine(temp);
            }
            Console.ReadKey();

        }
        static int[] startTime = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
        static int[] finishTime = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
        /// <summary>
        /// 贪心算法解决会议活动安排问题
        /// </summary>
        /// <param name="startActivityNumber">活动开始的索引</param>
        /// <param name="endActivityNumber">活动结束的索引</param>
        /// <param name="startTime">活动开始时间</param>
        /// <param name="endTime">活动结束时间</param>
        /// <returns></returns>
        public static List<int> ActivitySelection(int startActivityNumber,int endActivityNumber,int startTime ,int endTime)
        {
            if (startActivityNumber > endActivityNumber || startTime >= endTime)
            {
                return new List<int>();
            }
            //找到结束时间最早的活动 
            int tempNumber = 0;
            for (int number = startActivityNumber; number <= endActivityNumber; number++)
            {
                if (Program.startTime[number] >= startTime && finishTime[number] <= endTime)
                {
                    tempNumber = number;
                    break;
                }
            }
            List<int> list = ActivitySelection(tempNumber + 1, endActivityNumber, finishTime[tempNumber], endTime);
            list.Add(tempNumber);
            return list;
        }
    }

코인 변경 문제

/* 이 문제는 일상생활에서 더 흔하게 발생합니다. 각각 1위안, 2위안, 5위안, 10위안, 20위안, 50위안, 100위안의 c0, c1, c2, c3, c4, c5, c6 지폐가 있다고 가정합니다. 이제 이 돈으로 K 위안을 지불하려면 최소한 몇 장의 지폐를 사용해야 합니까? 그리디 알고리즘이라는 아이디어를 활용하면 각 단계에서 액면가가 큰 지폐만 최대한 사용할 수 있다는 것은 자명합니다. 우리는 일상생활에서 자연스럽게 이것을 합니다. 값은 프로그램에서 오름차순으로 정렬되었습니다. */


public class QianBiZhaoLing {
    public static void main(String[] args) 
    {
        //人民币面值集合
        int[] values = { 1, 2, 5, 10, 20, 50, 100 };
        //各种面值对应数量集合
        int[] counts = { 3, 1, 2, 1, 1, 3, 5 };
        //求442元人民币需各种面值多少张
        int[] num = change(442, values, counts);
        print(num, values);
    }

    public static int[] change(int money, int[] values, int[] counts) {
        //用来记录需要的各种面值张数
        int[] result = new int[values.length];

        for (int i = values.length - 1; i >= 0; i--) {
            int num = 0;
            //需要最大面值人民币张数
            int c = min(money / values[i], counts[i]);
            //剩下钱数
            money = money - c * values[i];
            //将需要最大面值人民币张数存入数组
            num += c;
            result[i] = num;
        }
        return result;
    }

    /**
     * 返回最小值
     */
    private static int min(int i, int j) {
        return i > j ? j : i;
    }
    
    private static void print(int[] num, int[] values) {
        for (int i = 0; i < values.length; i++) {
            if (num[i] != 0) {
                System.out.println("需要面额为" + values[i] + "的人民币" + num[i] + "张");
            }
        }
    }
}

빠른 대기열 

정렬 효율성 일반적으로 여러 정렬 방법의 효율성이 상대적으로 높기 때문에 자주 사용됩니다. 빠른 정렬 아이디어와 함께 분할 및 정복 방법도 매우 실용적입니다.

매개변수 int 배열, 왼쪽 인덱스, 오른쪽 인덱스

1. 왼쪽 인덱스가 오른쪽 인덱스보다 작은 경우 if(left < right) { }

2. 기준값에 값을 할당하고, 왼쪽 인덱스에 값을 할당하고, 오른쪽 인덱스에 값을 할당합니다.

        baseValue = arr[왼쪽],leftIndex = 왼쪽,rightIndex = 오른쪽。

3. 바깥쪽 고리는 오른쪽에서 왼쪽으로, 왼쪽에서 오른쪽으로 총 3개의 고리가 있습니다.

while(true && leftIndex < rightIndex) 

           while(true && leftIndex < rightIndex){} 기준값보다 작은 값을 오른쪽에서 왼쪽으로 찾습니다.

                 if(arr[right] < = baseValue) 오른쪽 값이 기본 값보다 작은 경우

                        arr[left] = arr[right] 왼쪽의 인덱스 값은 오른쪽의 작은 값과 같습니다.

                 그렇지 않으면 오른쪽 인덱스가 1만큼 감소합니다.

                        rightIndex--; 오른쪽 인덱스 빼기 1

          while(ture && leftIndex < rightIndex){} 왼쪽에서 오른쪽으로 기준값보다 큰 값을 찾습니다.

                if(arr[leftIndex] > arr[rightIndex]) 왼쪽 값이 기본 값보다 큰 경우

                        arr[rightIndex] = arr[leftIndex] 오른쪽 인덱스의 값은 왼쪽에서 찾은 대략적인 값과 같습니다.

                그렇지 않으면

                         왼쪽 인덱스++;

4. 3번의 while(true && leftIndex < rightIndex) 이후 왼쪽의 값은 기준값보다 작고, 오른쪽의 값은 기준값보다 크고 leftIndex = rightIndex, arr[left] = 기본값.

5. 분할 정복 방법은 왼쪽에서 leftIndex-1로 재귀적으로, 그리고 leftIndex+1에서 오른쪽으로 재귀적으로 작동합니다.

      QuickSort(dataArray, left, leftIdex - 1);
      QuickSort(dataArray, leftIdex + 1, right);

class Program
	{
		/// <summary>
		/// 对数组dataArray中索引从left到right之间的数做排序
		/// </summary>t
		/// <param name="dataArray">要排序的数组</param>
		/// <param name="left">要排序数据的开始索引</param>
		/// <param name="right">要排序数据的结束索引</param>
		static void QuickSort(int[] dataArray, int left, int right)
		{
			if (left < right)
			{
				//基准数, 把比它小或者等于它的 放在它的左边,然后把比它大的放在它的右边
				int baseValue = dataArray[left];
				int leftIdex = left;
				//用来做循环的标志位
				int rightIndex = right;
				//leftIdex==rightIndex,说明我们找到了一个中间位置,这个中间位置就是基准数应该所在的位置 
				while (true && leftIdex < rightIndex)
				{
					//从后往前比较(从右向左比较) 找一个比基数小(或者=)的数字,放在我们的坑里 坑位于leftIdex的位置
					while (true && leftIdex < rightIndex)
					{
						if (dataArray[rightIndex] <= baseValue)
						{
							//找到了一个比基准数 小于或者等于的数子,应该把它放在leftIdex的左边
							dataArray[leftIdex] = dataArray[rightIndex];
							break;
						}
						else
						{
							rightIndex--;//向左移动 到下一个数字,然后做比较
						}
					}

					//从前往后(从左向右)找一个比baseValue大的数字,放在我们的坑里面 现在的坑位于rightValue的位置
					while (true && leftIdex < rightIndex)
					{
						if (dataArray[leftIdex] > baseValue)
						{
							dataArray[rightIndex] = dataArray[leftIdex];
							break;
						}
						else
						{
							leftIdex++;
						}
					}
				}
				//跳出循环 现在i==j i是中间位置
				dataArray[leftIdex] = baseValue;// left -i- right

				QuickSort(dataArray, left, leftIdex - 1);
				QuickSort(dataArray, leftIdex + 1, right);
			}
		}

		static void Main(string[] args)
		{
			int[] data = new int[] { 42, 20, 17, 27, 13, 8, 17, 48 };

			QuickSort(data, 0, data.Length - 1);

			foreach (var temp in data)
			{
				Console.Write(temp + " ");
			}
			Console.ReadKey();
		}

이진 트리 정렬

트리 노드

    class BSNode
    {
        public BSNode LeftChild { get; set; }
        public BSNode RightChild { get; set; }
        public BSNode Parent { get; set; }
        public int Data { get; set; }
        public BSNode()
        {

        }
        public BSNode(int item)
        {
            this.Data = item;
        }
    }

이진 트리

    class BSTree
    {
        BSNode root = null;

        //添加数据
        public void Add(int item)
        {
            BSNode newNode = new BSNode(item);
            if (root == null)
            {
                root = newNode;
            }
            else
            {
                BSNode temp = root;
                while (true)
                {
                    if (item >= temp.Data)
                    {
                        //放在temp的右边
                        if (temp.RightChild == null)
                        {
                            temp.RightChild = newNode;
                            newNode.Parent = temp;
                            break;
                        }
                        else
                        {
                            temp = temp.RightChild;
                        }
                    }
                    else//放在temp的左边
                    {
                        if (temp.LeftChild == null)
                        {
                            temp.LeftChild = newNode;
                            newNode.Parent = temp;
                            break;
                        }
                        else
                        {
                            temp = temp.LeftChild;
                        }
                    }
                }
            }
        }

        public void MiddleTraversal()
        {
            MiddleTraversal(root);
        }
        private void MiddleTraversal(BSNode node)
        {
            if (node == null) return;

            MiddleTraversal(node.LeftChild);
            Console.Write(node.Data + " ");
            MiddleTraversal(node.RightChild);

        }
        public bool Find(int item)
        {
            //return Find(item, root);

            BSNode temp = root;
            while (true)
            {
                if (temp == null) return false;
                if (temp.Data == item) return true;
                if (item > temp.Data)
                    temp = temp.RightChild;
                else
                    temp = temp.LeftChild;
            }
        }


        private bool Find(int item,BSNode node)
        {
            if (node == null) return false;
            if (node.Data == item)
            {
                return true;
            }
            else
            {
                if (item > node.Data)
                {
                    return Find(item, node.RightChild);
                }
                else
                {
                    return Find(item, node.LeftChild);
                }
            }
        }

        public bool Delete(int item)
        {
            BSNode temp = root;
            while (true)
            {
                if (temp == null) return false;
                if (temp.Data == item)
                {
                    Delete(temp);
                    return true;
                }
                if (item > temp.Data)
                    temp = temp.RightChild;
                else
                    temp = temp.LeftChild;
            }
        }
        public void Delete(BSNode node)
        {
            if (node.LeftChild == null && node.RightChild == null)
            {
                if (node.Parent == null)
                {
                    root = null;
                }else if (node.Parent.LeftChild == node)
                {
                    node.Parent.LeftChild = null;
                }
                else if(node.Parent.RightChild==node)
                {
                    node.Parent.RightChild = null;
                }
                return;
            }
            if (node.LeftChild == null && node.RightChild != null)
            {
                node.Data = node.RightChild.Data;
                node.RightChild = null;
                return;
            }
            if (node.LeftChild != null && node.RightChild == null)
            {
                node.Data = node.LeftChild.Data;
                node.LeftChild = null;
                return;
            }

            BSNode temp = node.RightChild;
            while (true)
            {
                if (temp.LeftChild != null)
                {
                    temp = temp.LeftChild;
                }
                else
                {
                    break;
                }
            }
            node.Data = temp.Data;
            Delete(temp);
        }
    }

옮기다

    class Program
    {
        static void Main(string[] args)
        {
            BSTree tree = new BSTree();
            int[] data = { 62, 58, 88, 47, 73, 99, 35, 51, 93, 37 };
            foreach (int t in data)
            {
                tree.Add(t);
            }
            // 二叉树中序输出
            tree.MiddleTraversal();
            Console.WriteLine();
            Console.WriteLine(tree.Find(99));
            Console.WriteLine(tree.Find(100));
            tree.Delete(35);
            tree.MiddleTraversal();
            Console.WriteLine();
            tree.Delete(62);
            tree.MiddleTraversal(); 
            Console.WriteLine();
            Console.ReadKey();
        }
    }

힙 정렬

	class Program
	{
		static void Main(string[] args)
		{
			int[] data = { 50, 10, 90, 30, 70, 40, 80, 60, 20 };
			HeapSort(data);
			foreach (int i in data)
			{
				Console.Write(i + " ");
			}
			Console.WriteLine();
			Console.ReadKey();
		}

		public static void HeapSort(int[] data)
		{
			//遍历这个树的所有非叶结点(小树) ,挨个把所有的小子树,变成子大顶堆
			for (int i = data.Length / 2; i >= 1; i--)
			{
				// 对小子树分别构造大顶堆
				HeapAjust(i, data, data.Length);
				//经过上面的for循环,是把二叉树变成了大顶堆
			}

			for (int i = data.Length; i > 1; i--)
			{	
				// 把构造好的大顶堆,堆顶和最后的值换一下
				int temp1 = data[0];
				data[0] = data[i - 1];
				data[i - 1] = temp1;
				HeapAjust(1, data, i - 1);
			}
		}

		/// <summary>
		/// 构造某个非叶子节点的大顶堆
		/// </summary>
		/// <param name="numberToAjust">要子树调整的父节点</param>
		/// <param name="data">整个数组</param>
		/// <param name="maxNumber">最大索引</param>
		private static void HeapAjust(int numberToAjust, int[] data, int maxNumber)
		{
			//最大值结点的编号
			int maxNodeNumber = numberToAjust;
			int tempI = numberToAjust;
			//把i结点的子树变成大顶堆
			while (true)
			{
				// 左子节点索引
				int leftChildNumber = tempI * 2;
				// 右子节点索引
				int rightChildNumber = leftChildNumber + 1;
				// 左子节点索引小于最大索引,左子节值 > 父节点值
				if (leftChildNumber <= maxNumber && data[leftChildNumber - 1] > data[maxNodeNumber - 1])
				{
					maxNodeNumber = leftChildNumber;
				}
				// 右子节点索引小于最大索引,右子节值 > 父节点值
				if (rightChildNumber <= maxNumber && data[rightChildNumber - 1] > data[maxNodeNumber - 1])
				{
					maxNodeNumber = rightChildNumber;
				}
				// 最大节点编号不等于父界面编号,这俩交换一下位置
				if (maxNodeNumber != tempI)
				{
					int temp = data[tempI - 1];
					data[tempI - 1] = data[maxNodeNumber - 1];
					data[maxNodeNumber - 1] = temp;
					tempI = maxNodeNumber;
				}
				else
				{
					break;
				}
			}
		}
	}

추천

출처blog.csdn.net/qq_35647121/article/details/131891535