文章目录
堆排序
堆的定义:堆是具有下列性质的完全二叉树;每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于等于其左右孩子结点的值,称为小顶堆。
堆排序:
理论部分就记录完毕了。接下来上代码。
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背包问题
今天的笔记整理到此结束,本贴会不定时持续更新,直到补充完数据结构和算法的知识。