バブルソート
基本的な考え方は、隣接するレコードのキー コードを比較し、前のレコードのキー コードが次のレコードのキー コードより大きければ交換し、そうでない場合は交換しません。
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. 中央の数値を求めます。中央値の前の数値が最大所得値として計算され、中央値の後の数値が最大入力値として計算され、この 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 アイテムの容量を持つバックパック。
重みは、weittht[1] weittht[2] ... weittht[i] (kg) です。
値は、price[1] p[2] ... p[i] (元)
バックパックの合計価値を最大化するには、バックパックにどのようなアイテムを入れることができますか? 最大値はいくらですか?
容量 m (kg) のバックパックに入れる i 個のオブジェクトの最大値 MaxValue[i,m]
各アイテム i には、ナップザックに入れるか入れないかの 2 つの選択肢しかないため、この問題は 0-1 ナップザック問題と呼ばれます。
1. リュックの容量を超えた物を入れた場合は捨ててください。
2. バックパックに入れた価値を価値として数え、バックパックに入らなかった価値を価値として数えて比較し、バックパックに入れた価値が多ければ入れ、小さければ入れてください。次に、分割統治法を使用して順番に検索し、毎回得られた結果を 2 次元配列に格納します。2 つの添え字を持つデータ グループ
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;
}
}
貪欲なアルゴリズム
会議スケジュールの競合の問題
会議活動のスケジュールの競合の問題を解決し、1 日に最もスケジュールされている活動のインデックスを見つけます。
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] 右のインデックスの値は、左側の近似値と同じです。
それ以外の場合
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;
}
}
}
}