算法和数据结构笔记

堆排序

堆的定义:堆是具有下列性质的完全二叉树;每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于等于其左右孩子结点的值,称为小顶堆。

堆排序:

在这里插入图片描述
理论部分就记录完毕了。接下来上代码。
data对应的二叉树是:在这里插入图片描述

 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 (int i = data.Length; i > 1; i--)
    {
        //把编号1和编号i位置进行交换
        //1到(i-1)构造成大顶堆
        int temp1 = data[0];
        data[0] = data[i - 1];
        data[i - 1] = temp1;
        HeapAjust(1, data, i-1);
    }
}

public static void HeapAjust(int numbetoAjust,int[] data,int maxNumber)
{
    int maxNodeNumber = numbetoAjust;//最大结点的编号
    int tempI = numbetoAjust;
    while (true)
    {
        //把i结点的子树变成大顶堆
        int leftChildNumber = tempI * 2;
        int rightChildNumber = leftChildNumber + 1;
        if (leftChildNumber <= maxNumber && data[leftChildNumber - 1] > data[maxNodeNumber - 1])
        {
            maxNodeNumber = leftChildNumber;
        }
        if (rightChildNumber <= maxNumber && data[leftChildNumber - 1] > data[maxNodeNumber - 1])
        {
            maxNodeNumber = rightChildNumber;
        }
        if (maxNodeNumber != tempI)//发现了一个比i更大的子结点,交换i和maxnodenumber里面的数据
        {
            int temp = data[tempI - 1];
            data[tempI - 1] = data[maxNodeNumber - 1];
            data[maxNodeNumber - 1] = temp;
            tempI = maxNodeNumber;
        }
        else
        {
            break;
        }
    }
}

控制台程序输出的结果:在这里插入图片描述

动态规划算法

什么是动态规划?

动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。

动态规划和分治法相似,都是通过组合子问题的解来求解原问题。分治法将问题划分成互不相交的子问题,递归求解子问题,再将他们的解组合起来,求出原问题的解。与之相法,动态规划应用于子问题重叠的情况,既不同的子问题具有公共子问题。在这种情况下,分治算法会做出许多不必要的工作,它会反复求解那些公共子问题。而动态规划算法对每个子子问题只求解一次,将结果保存到表格中,从而无需每次求解一个子子问题都要重新计算。

动态规划-钢条切割问题

问题如下:
截图
在这里插入图片描述
第二种求解方案是优于第一张方案的 所以下面的代码以第二种为例写一遍
在这里插入图片描述

static void Main(string[] args)
{
    int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
    Console.WriteLine(UpDown(0, p));
    Console.WriteLine(UpDown(1, p));
    Console.WriteLine(UpDown(2, p));
    Console.WriteLine(UpDown(3, p));
    Console.WriteLine(UpDown(4, p));
    Console.WriteLine(UpDown(5, p));
    Console.WriteLine(UpDown(6, p));
    Console.WriteLine(UpDown(7, p));
    Console.WriteLine(UpDown(8, p));
    Console.WriteLine(UpDown(9, p));
    Console.WriteLine(UpDown(10, p));
    Console.ReadKey();
}

public static int UpDown(int n,int[] p)
{
    if (n == 0) return 0;
    int tempMaxPrice = 0;
    for(int i = 1; i < n + 1; i++)
    {
        int maxPrice = p[i] + UpDown(n - i, p);
        if (maxPrice > tempMaxPrice)
        {
            tempMaxPrice = maxPrice;
        }
    }
    return tempMaxPrice;
}

由上面的案例可以看出,这种递归会反复调用已经求解过的结果造成时间的浪费,所以我们提出下面的动态规范的两种方法来优化此算法,用内存空间换取时间。
在这里插入图片描述
下面是改进过的代码:
第一种方法:(带备忘)自顶向下的动态规划

private static Dictionary<int, int> result = new Dictionary<int, int>();
static void Main(string[] args)
{
    int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
    Console.WriteLine(UpDown(0, p));
    Console.WriteLine(UpDown(1, p));
    Console.WriteLine(UpDown(2, p));
    Console.WriteLine(UpDown(3, p));
    Console.WriteLine(UpDown(4, p));
    Console.WriteLine(UpDown(5, p));
    Console.WriteLine(UpDown(6, p));
    Console.WriteLine(UpDown(7, p));
    Console.WriteLine(UpDown(8, p));
    Console.WriteLine(UpDown(9, p));
    Console.WriteLine(UpDown(10, p));
    Console.ReadKey();
}

public static int UpDown(int n, int[] p)
{
    if (n == 0) return 0;
    if (result.ContainsKey(n) && 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);
        if (maxPrice > tempMaxPrice)
        {
            tempMaxPrice = maxPrice;
        }
    }
    result[n] = tempMaxPrice;
    return tempMaxPrice;
}

第二种方法:(带备忘)自底向上的动态规划,这个比第一种方法还要进一步优化。因为大的子问题依赖小的子问题。

private static Dictionary<int, int> result = new Dictionary<int, int>();
        static void Main(string[] args)
        {
            int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
            result[0] = 0;
            Console.WriteLine(BottomUp(0, p));
            Console.WriteLine(BottomUp(1, p));
            Console.WriteLine(BottomUp(2, p));
            Console.WriteLine(BottomUp(3, p));
            Console.WriteLine(BottomUp(4, p));
            Console.WriteLine(BottomUp(5, p));
            Console.WriteLine(BottomUp(6, p));
            Console.WriteLine(BottomUp(7, p));
            Console.WriteLine(BottomUp(8, p));
            Console.WriteLine(BottomUp(9, p));
            Console.WriteLine(BottomUp(10, p));
            Console.ReadKey();
        }

        public static int BottomUp(int n,int[] p)
        {
            for(int i = 1; i < n + 1; i++)
            {
                //下面取得  钢条长度为i的时候的最大收益
                int tempMaxPrice = -1;
                for(int j = 1; j <= i; j++)
                {
                    int maxPrice = 0;
                    if (result.ContainsKey(i - j))
                    {
                        maxPrice = p[j] + result[i - j];
                    }
                    if (maxPrice > tempMaxPrice)
                    {
                        tempMaxPrice = maxPrice;
                    }
                    result[i] = tempMaxPrice;
                }
            }
            return result[n];
        }

动态规划 0-1背包问题

在这里插入图片描述

今天的笔记整理到此结束,本贴会不定时持续更新,直到补充完数据结构和算法的知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值