冒泡排序
基本思想是:将相邻的记录的关键码进行比较,若前面记录的关键码大于后面记录的关键码,则将它们交换,否则不交换。
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、三者比较大小,返回哪天买入,哪天卖出
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个物品。
重量分别为weitht[1] weitht[2] ... weitht[i] (kg)
价值分别为price[1] p[2] ... p[i] (元)
将哪些物品放入背包可以使得背包的总价值最大?最大价值是多少?
i个物体放入容量为m(kg)的背包的最大价值MaxValue[i,m]
对于每种物品i只有两种选择,即装入背包或不装入背包,,因此该问题被称为0-1背包问题
1、放入的物品如果大于背包容量就舍弃
2、放入背包的价值算一个值,不放入背包的价值算一个值,对比一下,放入背包的值大就放入,小就不放入,然后再用分治法,依次求,把每次求得的结果用二维数组存起来。有两个下标的数据组
二维数组的声明如下:
int[,] array=new 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元,至少要用多少张纸币?用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。在日常生活中我们自然而然也是这么做的。在程序中已经事先将Value按照从小到大的顺序排好。*/
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[left],leftIndex = left,rightIndex = right。
3、一共三个此循环,外循环,从右往左,从左往右
while(true && leftIndex < rightIndex)
while(true && leftIndex < rightIndex){} 从右往左找到比基准值小的
if(arr[right] < = baseValue) 如果右边的比基准值小
arr[left] = arr[right] 左边的索引值等于右边找出的小值
else 否则右索引减1
rightIndex--; 右索引减1
while(ture && leftIndex < rightIndex){} 从左往右找比基准值大的
if(arr[leftIndex] > arr[rightIndex]) 如果左边的大于基准值
arr[rightIndex] = arr[leftIndex] 右边索引的值等于左边找到的大致
else 否则
leftIndex++;
4、三个while(true && leftIndex < rightIndex)之后,左边的值都比基础值小,右边的都比基础值大并且leftIndex = rightIndex,arr[left] = baseValue。
5、分治法操作递归,对左边left到leftIndex-1递归,对右边leftIndex+1到right递归
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;
}
}
}
}