目录
4.需求:有个88笔费用记录,总额3亿,金额在300万~800万之间,随机数如何实现?并记录总耗时。
1.字符串和整型之间的转换
1.1字符串转化为整型:
一种是使用Parse()方法,int.Parse()方法在无法解析字符串时会直接抛出FormatException。
string str = "123";
int a = int.Parse(str);
Console.WriteLine(a);
一种是Convert.ToInt32()方法,Convert.ToInt32()方法尝试将字符串的参数转换为32位有符号整数。如果字符串不能转换为整数,则会抛出FormatException或OverflowException。
int b = Convert.ToInt32(str);
Console.WriteLine(b);
还有一种 int.TryParse()方法,如果你不确定字符串是否一定可以转换为整数,那么使用int.TryParse()方法是一个更好的选择。这个方法尝试将字符串的参数转换为整数,并返回一个布尔值以指示转换是否成功。如果转换成功,out参数将包含转换后的整数。
if (int.TryParse(str, out int number))
{
Console.WriteLine(number); // 输出: 123
}
else
{
Console.WriteLine("转换失败");
}
1.2整型转化为字符串:
一种方法是ToString()方法 ,对于任何整数类型(如int、long等),都可以直接调用其ToString()方法将其转换为字符串。
一种方法是可以直接和空串进行相加,任何类型和字符串连接结果都是字符串。
int n = 123;
//第一种方式
Console.WriteLine(Convert.ToString(n));
//第二种方式
Console.WriteLine(""+n);
2.获字符串和日期之间的转换
2.1获取当前日期
使用datetime模块的datetime.now()方法,可以获取当前的日期和时间。
DateTime currentTime = DateTime.Now;
2.2字符串转日期
可以使用Parse()或方法。
string s = "2024-07-04";
DateTime date = DateTime.Parse(s);
Console.WriteLine(date);
2.3日期转字符串
使用ToString()方法
DateTime now = DateTime.Now;
// 使用默认的格式(依赖于当前的文化设置)
string defaultString = now.ToString();
// 使用自定义的格式
string customString = now.ToString("yyyy-MM-dd HH:mm:ss");
Console.WriteLine("默认格式: " + defaultString);
Console.WriteLine("自定义格式: " + customString);
2.4提取日期中的年月日等信息
DateTime dt = new DateTime(2024, 7, 4, 9, 51, 09);
Console.WriteLine(dt.ToString());
Console.WriteLine(dt.Year.ToString());
Console.WriteLine(dt.Month.ToString());
Console.WriteLine(dt.Day.ToString());
3.举例一维、二维、三维数组
在C#中,数组是一种数据结构,用于在计算机内存中连续存储相同类型的数据项。数组中的每个元素都可以通过索引来访问,索引通常是一个整数,表示元素在数组中的位置。数组的大小在声明时必须指定,并且之后不能更改。
3.1一维数组
一维数组有三种创建形式:
//三种方式
int[] a1 = new int[3];
int[] a2 = new int[3] { 1, 2, 3 };
int[] a3 = { 1, 2, 3 };
//若是不进行赋值,初始化值都为0
产生长度固定的随机数组:
int[] a4 = new int[10];
Random rd = new Random();
for (int i = 0; i < a4.Length; i++)
{
a4[i] = rd.Next(1, 101);//左闭右开
}
for (int i = 0; i < a4.Length; i++)
{
Console.Write(a4[i] + " ");
}
3.2二维数组
二维数组可以看作是一个表格,它有两个维度:行和列。每个元素可以通过行索引和列索引来访问。
//创建一个二维数组
int[,] a2 = new int[2,3];//声明一个两行三列的二维数组
int[,] a2 = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };
遍历二维数组:GetLength()方法,getlength获取维度长度而不是数组长度,维度从0开始
for (int i = 0; i < a2.GetLength(0); i++)
{
for (int j = 0; j < a2.GetLength(1); j++)
{
Console.Write(a2[i, j] + " ");
}
Console.WriteLine();
}
3.3三维数组
三维数组可以想象成是由多个二维数组(即多个表格)堆叠而成的结构,它有三个维度:深度、行和列。
int[,,] a3 = new int[2, 2, 2] { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
a3[0, 0, 0] = 100;
a3[1, 1, 1] = 999;
for (int i = 0; i < a3.GetLength(0); i++)
{
for (int j = 0; j < a3.GetLength(1); j++)
{
for (int k = 0; k < a3.GetLength(2); k++)
{
Console.Write(a3[i, j, k] + " ");
}
Console.WriteLine();
}
Console.WriteLine();
}
4.需求:有个88笔费用记录,总额3亿,金额在300万~800万之间,随机数如何实现?并记录总耗时。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
class Program
{
static void Main(string[] args)
{
int totalRecords = 88;
decimal totalAmountNeeded = 300000000m; // 3亿
decimal minAmount = 3000000m; // 300万
decimal maxAmount = 8000000m; // 800万
Stopwatch stopwatch = Stopwatch.StartNew();
Random random = new Random();
List<decimal> expenses = new List<decimal>(); // 使用List以动态管理大小
decimal currentTotal = 0m;
decimal average = (decimal)Math.Ceiling(totalAmountNeeded / totalRecords); // 使用Ceiling确保平均金额向上取整
for (int i = 0; i < totalRecords; i++)
{
// 允许一定的波动,但不超过平均金额的10%
decimal fluctuation = (decimal)random.NextDouble() * (average / 10);
fluctuation -= average / 20; // 使波动范围在-10%到+10%之间
decimal amount = average + fluctuation;
// 确保金额在合理范围内
amount = Math.Max(minAmount, Math.Min(amount, maxAmount));
expenses.Add(amount); // 将金额添加到列表中
currentTotal += amount;
}
// 打印结果
foreach (var expense in expenses)
{
Console.WriteLine(expense.ToString("N0"));
}
Console.WriteLine($"总金额: {currentTotal.ToString("N0")}");
// 输出总耗时
Console.WriteLine($"总耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
}
}
输出结果:
5.常见的集合类型的存储结构和它们的作用以及优缺点
常见的集合类型有以下几种:
5.1静态数组 (Array)
存储结构:固定大小的连续内存块。
作用:存储固定数量的相同类型的数据项。
优点:
- 访问速度快(通过索引直接访问)。
- 占用内存少(因为是连续存储)。
缺点:
- 大小固定,不能动态增加或减少元素。
int[] a1 = { 1, 2, 3, 4, 5 };//静态数组,一旦分配完空间内存空间不允许改变
a1[5] = 5;//超过数组范围
5.2动态数组 ArrayList
存储结构:内部使用数组,但能够动态调整大小。
作用:提供动态调整大小的数组功能,但不是类型安全的。
优点:
- 动态扩容。
- 可以存储任意类型的对象。
缺点:
- 不是类型安全的,存在装箱和拆箱的开销。
- 性能通常不如List<T>。
using System.Collections;
ArrayList arrayList = new ArrayList();
//添加元素
arrayList.Add(100);
arrayList.Add(400);
arrayList.Add(300);
arrayList.Add(400);
arrayList.Add(500);//超过内存申请的空间,自动扩容(扩容策略:翻倍)
Console.WriteLine("动态数组的容量:{0}", arrayList.Capacity);
Console.WriteLine("动态数组的元素个数:{0}", arrayList.Count);
//删除元素
arrayList.Remove(500);//直接删除
arrayList.RemoveAt(0);//按索引删除
Console.WriteLine("动态数组的容量:{0}", arrayList.Capacity);
Console.WriteLine("动态数组的元素个数:{0}", arrayList.Count);
arrayList.Sort();//排序
arrayList.Clear();//清空
foreach (int item in arrayList)
{
Console.WriteLine(item);
}
5.3动态数组 List<T>
存储结构:内部使用数组,但能够动态调整大小,并且是类型安全的。
作用:提供类型安全的动态数组功能。
优点:
- 动态扩容。
- 类型安全,无需装箱和拆箱。
- 提供丰富的功能,如排序、搜索等。
缺点:
- 在列表中间插入或删除元素时可能需要移动大量元素,影响性能。
using System.Collections;
ArrayList arrayList = new ArrayList();
arrayList.Add(100);
arrayList.Add("200");
Console.WriteLine("执行正常");
foreach (var i in arrayList)
{
Console.WriteLine(i);
}
//泛型,编译器编译时可以进行类型检查
List<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
//list.Add("200");//泛型在编译时就进行类型检查,防止运行时报错
Console.WriteLine("容量:" + list.Capacity);
Console.WriteLine("个数:" + list.Count);
list.Remove(200);
list.RemoveAt(1);
list.Sort();
foreach (int i in list)
{
Console.WriteLine(i);
}
5.4链表 LinkedList<T>
存储结构:由一系列节点组成,每个节点包含数据和指向下一个节点的链接。
作用:提供在任意位置高效插入和删除元素的能力。
优点:
- 在链表中间插入或删除元素时性能高(不需要移动其他元素)。
缺点:
- 随机访问速度慢(需要从头或尾遍历)。
- 占用内存可能比动态数组多(因为每个节点都需要额外的存储空间来存储链接)。
LinkedList<string> linkedList = new LinkedList<string>();
linkedList.AddFirst("陈晨");
linkedList.AddFirst("陈希");
linkedList.AddFirst("陈冲");
linkedList.AddLast("陈川");
linkedList.Remove("陈晨");
linkedList.Remove("陈晨");
var node = linkedList.Find("陈冲");
Console.WriteLine("当前节点的值:" + node.Value);
foreach (string linked in linkedList)
{
Console.WriteLine(linked);
}
linkedList.AddFirst和 linkedList.AddLast是.NET中LinkedList<T>类提供的两个方法,它们的主要区别在于向链表中添加元素时的位置不同。
- linkedList.AddFirst(T value):这个方法用于在链表的开头(即头部)添加一个新的元素。如果链表是空的,那么这个新元素将成为链表中唯一的元素。如果链表已经包含元素,新元素将被添加到链表的第一个元素之前,成为新的第一个元素。
- linkedList.AddLast(T value):这个方法用于在链表的末尾(即尾部)添加一个新的元素。如果链表是空的,那么这个新元素同样会成为链表中唯一的元素。如果链表已经包含元素,新元素将被添加到链表的最后一个元素之后,成为新的最后一个元素。
这两个方法都接受一个类型为T的参数value,其中T是LinkedList<T>中元素的类型。它们都会使链表的Count属性增加1,但添加元素的位置不同。
5.5队列Queue<T>
存储结构:
- 队列是一种先进先出(FIFO)的数据结构。在内部,它通常使用数组或链表来实现,但具体实现是.NET Framework的内部细节,用户不需要关心。
作用:
- 用于存储元素的集合,但元素的添加(入队)是在集合的一端进行,而元素的移除(出队)则是在另一端进行。这种特性使得队列非常适合于处理一系列需要按顺序处理的元素。
优点:
- 提供了高效的元素入队和出队操作。
- 元素的顺序性保证了数据处理的顺序。
缺点:
- 如果需要频繁地在队列中间进行插入或删除操作,则性能可能不佳。
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Queue<int> queue = new Queue<int>();
// 入队
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
// 遍历队列
foreach (var item in queue)
{
Console.WriteLine(item);
}
// 出队
Console.WriteLine("出队元素: " + queue.Dequeue());
// 再次遍历队列
Console.WriteLine("剩余队列:");
foreach (var item in queue)
{
Console.WriteLine(item);
}
}
}
5.6栈Stack<T>
存储结构:
- 栈是一种后进先出(LIFO)的数据结构。同样,它的内部实现可能是数组或链表,但这对于用户来说是透明的。
作用:
- 用于存储元素的集合,但元素的添加(入栈)和移除(出栈)都在集合的同一端进行。这种特性使得栈非常适合于处理需要后进先出顺序处理的元素。
优点:
- 提供了高效的元素入栈和出栈操作。
- 元素的顺序性使得栈成为递归和函数调用栈等场景的理想选择。
缺点:
- 如果需要频繁地在栈中间进行插入或删除操作,则性能可能不佳。
- 访问栈中的非顶部元素可能比较耗时。
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
// 入栈
stack.Push(1);
stack.Push(2);
stack.Push(3);
// 遍历栈
Array.ForEach(stack.ToArray(), item => Console.WriteLine(item));
// 出栈
Console.WriteLine("出栈元素: " + stack.Pop());
// 再次遍历栈
Console.WriteLine("剩余栈:");
Array.ForEach(stack.ToArray(), item => Console.WriteLine(item));
}
}