C#初步了解复杂数据类型,函数方法和排序

1.复杂数据类型

(1)枚举

枚举是一组命名整型常量。枚举类型是使用 enum 关键字声明的。

CSHARP 枚举是值类型。换句话说,枚举包含自己的值,且不能继承或传递继承。

enum <enum_name>
{ 
    enumeration list 
};

其中,

  • enum_name 指定枚举的类型名称。
  • enumeration list 是一个用逗号分隔的标识符列表。

枚举列表中的每个符号代表一个整数值,一个比它前面的符号大的整数值。默认情况下,第一个枚举符号的值是 0.例如:

enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };
(2)数组

数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合,通常认为数组是一个同一类型变量的集合。

声明数组变量并不是声明 number0、number1、…、number99 一个个单独的变量,而是声明一个就像 numbers 这样的变量,然后使用 numbers[0]、numbers[1]、…、numbers[99] 来表示一个个单独的变量。数组中某个指定的元素是通过索引来访问的。

所有的数组都是由连续的内存位置组成的。最低的地址对应第一个元素,最高的地址对应最后一个元素。

datatype[] arrayName;

其中,

  • datatype 用于指定被存储在数组中的元素的类型。
  • [ ] 指定数组的秩(维度)。秩指定数组的大小。
  • arrayName 指定数组的名称。

例如:

double[] balance;

初始化数组

声明一个数组不会在内存中初始化数组。当初始化数组变量时,您可以赋值给数组。

数组是一个引用类型,所以您需要使用 new 关键字来创建数组的实例。

例如:

double[] balance = new double[10];//声明数组
balance[0] = 4500.0;//数组赋值
double[] balance = { 2340.0, 4523.69, 3421.0};//声明数组的同时给数组赋值
int [] marks = new int[5]  { 99,  98, 92, 97, 95};//创建并初始化一个数组
int [] marks = new int[]  { 99,  98, 92, 97, 95};//也可以省略数组的大小
//您也可以赋值一个数组变量到另一个目标数组变量中。在这种情况下,目标和源会指向相同的内存位置:
int [] marks = new int[]  { 99,  98, 92, 97, 95};
int[] score = marks;

当您创建一个数组时,CSHARP 编译器会根据数组类型隐式初始化每个数组元素为一个默认值。例如,int 数组的所有元素都会被初始化为 0。

多维数组

CSHARP 支持多维数组。多维数组又称为矩形数组。

例如

string [,] names;//声明一个 string 变量的二维数组
int [ , , ] m;//声明一个 int 变量的三维数组

int [,] a = new int [3,4] {
 {0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
 {4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
 {8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
};

交错数组

交错数组是数组的数组,同时也是一维数组。

例如

int[][] scores = new int[5][];
for (int i = 0; i < scores.Length; i++) //声明交错数组
{
   scores[i] = new int[4];
}
int[][] scores = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};//初始化
//其中,scores 是一个由两个整型数组组成的数组 -- scores[0] 是一个带有 3 个整数的数组,scores[1] 是一个带有 4 个整数的数组。
(3)结构体

在 CSHARP 中,结构体是值类型数据结构。它使得一个单一变量可以存储各种数据类型的相关数据。struct 关键字用于创建结构体。

结构体是用来代表一个记录。假设您想跟踪图书馆中书的动态。您可能想跟踪每本书的以下属性:

  • Title
  • Author
  • Subject
  • Book ID

定义结构体

struct Books
{
   public string title;
   public string author;
   public string subject;
   public int book_id;
};  

用法

using System;
using System.Text;
     
struct Books
{
   public string title;
   public string author;
   public string subject;
   public int book_id;
};  

public class testStructure
{
   public static void Main(string[] args)
   {

      Books Book1;        /* 声明 Book1,类型为 Books */
      Books Book2;        /* 声明 Book2,类型为 Books */

      /* book 1 详述 */
      Book1.title = "C Programming";
      Book1.author = "Nuha Ali";
      Book1.subject = "C Programming Tutorial";
      Book1.book_id = 6495407;

      /* book 2 详述 */
      Book2.title = "Telecom Billing";
      Book2.author = "Zara Ali";
      Book2.subject =  "Telecom Billing Tutorial";
      Book2.book_id = 6495700;

      /* 打印 Book1 信息 */
      Console.WriteLine( "Book 1 title : {0}", Book1.title);
      Console.WriteLine("Book 1 author : {0}", Book1.author);
      Console.WriteLine("Book 1 subject : {0}", Book1.subject);
      Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);

      /* 打印 Book2 信息 */
      Console.WriteLine("Book 2 title : {0}", Book2.title);
      Console.WriteLine("Book 2 author : {0}", Book2.author);
      Console.WriteLine("Book 2 subject : {0}", Book2.subject);
      Console.WriteLine("Book 2 book_id : {0}", Book2.book_id);      

      Console.ReadKey();

   }
}

特点

在 CSHARP 中的结构与传统的 C 或 C++ 中的结构不同。CSHARP 中的结构有以下特点:

  • 结构可带有方法、字段、索引、属性、运算符方法和事件。

  • 结构可定义构造函数,但不能定义析构函数。但是,您不能为结构定义无参构造函数。无参构造函数(默认)是自动定义的,且不能被改变。

  • 与类不同,结构不能继承其他的结构或类。

  • 结构不能作为其他结构或类的基础结构。

  • 结构可实现一个或多个接口。

  • 结构成员不能指定为 abstract、virtual 或 protected。

  • 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构可以不使用 New 操作符即可被实例化。

  • 如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。

2.数值型和引用类型

引用类型:string,数组,类

值类型:其他

  • 区别

    int a = 10;
    int b = a;
    int [] arr1 = new int[4]  {1,2,3,4};
    int [] arr2 = arr1;
    Console.WriteLine("a={0},b={1}",a,b);
    //输出a=10,b=10
    Console.WriteLine("arr1[0]={0},arr2[0]={1}",arr1[0],arr2[0]);
    //输出arr[0]=1,arr2[0]=1;
    b = 5;
    arr2[0] = 5;
    Console.WriteLine("a={0},b={1}",a,b);
    //输出a=10,b=5
    Console.WriteLine("arr1[0]={0},arr2[0]={1}",arr1[0],arr2[0]);
    //输出arr[0]=5,arr2[0]=5;
    

    不难发现,值类型在相互赋值时,把内容拷贝给了对方,而引用类型的相互赋值时,是让两者指向同一个值

    原因为存储方式不同,值类型存储在栈(系统分配比较小但是快),引用类型存储在堆上(手动申请和释放,大而慢)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdXduLb2-1684920582190)(…/image/Snipaste_2023-04-27_12-22-58.png)]

特殊的引用类型string

因为CSHARP对字符串的特殊处理使它具有值类型的特点,当重新赋值时会在堆上重新分配空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xeLHNh5C-1684920582191)(../image/Snipaste_2023-04-27_12-32-33.png)]

**注意:**string虽然方便,但频繁重新赋值时,会产生内存垃圾

3.函数

  • 函数基础

    <Access Specifier> <Return Type> <Method Name>(Parameter List)
    {
       Method Body
    }
    

    下面是方法的各个元素:

    • Access Specifier:访问修饰符,这个决定了变量或方法对于另一个类的可见性。
    • Return type:返回类型,一个方法可以返回一个值。返回类型是方法返回的值的数据类型。如果方法不返回任何值,则返回类型为 void
    • Method name:方法名称,是一个唯一的标识符,且是大小写敏感的。它不能与类中声明的其他标识符相同。
    • Parameter list:参数列表,使用圆括号括起来,该参数是用来传递和接收方法的数据。参数列表是指方法的参数类型、顺序和数量。参数是可选的,也就是说,一个方法可能不包含参数。
    • Method body:方法主体,包含了完成任务所需的指令集。
  • ref和out

    在CSHARP中通过使用方法来获取返回值时,通常只能得到一个返回值。因此,当一个方法需要返回多个值的时候,就需要用到ref和out

    同时也可以在函数内部,改变传入的参数的值

    若要使用 ref 和out参数,则方法定义和调用方法都必须显式使用 ref和out 关键字。在方法中对参数的设置和改变将会直接影响函数调用之处(参数的初始值)。

    ref指定的参数在 函数调用前必须初始化,在内部可改可不改

    out指定的参数在不用初始化,但在函数内部(即方法中)赋初值。

    正确使用ref:

    class Program
        {
            static void Main(string[] args)
            {
                int x = 10;
                int y = 20;
                GetValue(ref x, ref  y);
                Console.WriteLine("x={0},y={1}", x, y);//输出x=333,y=444
                Console.ReadLine();
            }
            public void GetValue(ref int x, ref int y)
            {
                x = 333;
                y = 444;
            }
        }
    

    错误使用ref:

    class Program
        {
            static void Main(string[] args)
            {
                int x ;//未进行初始化,报错
                int y ;//未进行初始化,报错
                GetValue(ref x, ref  y);
                Console.WriteLine("x={0},y={1}", x, y);
                Console.ReadLine();
            }
            public void GetValue(ref int x, ref int y)
            {
                x = 333;
                y = 444;
            }
        }
    

    总结:使用ref 必须在 调用方法前 对其进行初识化操作

    正确使用out:

    class Program
    {
        static void Main(string[] args)
        {
            int x = 10;
            int y = 233;
            Swap(out x, out y);
            Console.WriteLine("x={0},y={1}", x, y);//输出x=333,y=444
            Console.ReadLine();
        }
    
        public static void Swap(out int a, out int b)
        {
            a = 333;   //对a,b 在方法内进行了初识化,不会报错
            b = 444;
        }
    }
    

    错误使用out:

    class Program
    {
        static void Main(string[] args)
        {
            int x = 10;
            int y = 233;
            Swap(out x, out y);
            Console.WriteLine("x={0},y={1}", x, y);
            Console.ReadLine();
        }
    
        public static void Swap(out int a, out int b)
        {
        	int tmp = a;
            a = b;   //a,b在函数内部没有赋初值,则出现错误。
            b = tmp;
        }
    }
    

    总结:out 的使用必须要在 方法内 进行 初始化 ,才不会报错

  • 变长参数和参数默认值

    比如要计算n个整数的和

    int SumInt(int a,int b, ......)//如果有n个参数就无法实现了
    

    变长参数关键字params

    int SumInt(params int[] arr)
    {
       	int sum;
    	foreach(int i in arr)
        {
            sum +=i;
        }
        return sum;
    }
    

    params 关键字后面必为数组,数组的类型可以使任意类型,函数参数中最多出现一个params参数且在最后出现,前面可以有n个其他参数。

    参数默认值

    如果在函数的参数处给形参赋值,则不输入实参时,默认为形参的值。

  • 函数重载

    和函数类型无关,名字相同,参数数量不同或者参数类型或顺序不同,命名一组功能相似的函数,减少函数名的数量,避免命名控件的污染,同时提升程序的可读性。

    ref和out,params可以算作重载 ,ref和out不能同时重载,可选参数不算重载

  • 递归函数

    让函数自己调用自己

    1.必须有结束调用的条件

    2.必须能够达到结束的目的

4. 初级排序

  • 冒泡排序

    冒泡排序是比较基础的排序算法之一,其思想是相邻的元素两两比较,较大的数下沉,较小的数冒起来,这样一趟比较下来,最大(小)值就会排列在一端。整个过程如同气泡冒起,因此被称作冒泡排序。
    冒泡排序的步骤是比较固定的:
    1>比较相邻的元素。如果第一个比第二个大,就交换他们两个。
    2>每趟从第一对相邻元素开始,对每一对相邻元素作同样的工作,直到最后一对。
    3>针对所有的元素重复以上的步骤,除了已排序过的元素(每趟排序后的最后一个元素),直到没有任何一对数字需要比较。

    using System;
    using System.Threading;
     
    namespace Sort
    {
        class Program
        {
            static void Main(string[] args)
            {
                
                int[] arr = {23, 44, 66, 76, 98, 11, 3, 9, 7};
                Console.WriteLine("排序前的数组:");
                foreach (int item in arr)
                {
                    Console.Write(item + ",");
                }
                Console.WriteLine();
                BubbleSort(arr);
                Console.WriteLine("排序后的数组:");
                foreach (int item in arr)
                {
                    Console.Write(item+",");
                }
                Console.WriteLine();
                Console.ReadKey();
            }
            static void BubbleSort(int[] arr)
            {
            	int temp = 0;
                for (int i = 0; i < arr.Length - 1; i++)
                {
                    for (int j = 0; j < arr.Length - 1 - i; j++)
                    {
                        if (arr[j] > arr[j + 1])
                        {
                            temp = arr[j + 1];
                            arr[j + 1] = arr[j];
                            arr[j] = temp;
                        }
                    }
                }
            }
        }
    }
    

    每一次循环产生一个最大数排到最后面,因此内循环中比较N-1-i次

    i为最大数的数量,外循环是N-1剩出来最右边的最大数

  • 选择排序

    选择排序是寻找当前数组中的最小元素/最大元素,然后将他们放到最前边/最后边的位置上去,然后以此类推,在剩余的数组中再次寻找,直到全部待排序的数据元素的个数为零。

    using System;
    using System.Threading;
     
    namespace Sort
    {
        class Program
        {
            static void Main(string[] args)
            {
                
                int[] arr = {23, 44, 66, 76, 98, 11, 3, 9, 7};
                Console.WriteLine("排序前的数组:");
                foreach (int item in arr)
                {
                    Console.Write(item + ",");
                }
                Console.WriteLine();
                SelectionSort(arr);
                Console.WriteLine("排序后的数组:");
                foreach (int item in arr)
                {
                    Console.Write(item+",");
                }
                Console.WriteLine();
                Console.ReadKey();
            }
            static void SelectionSort(int[] arr)
            {
                for (int i = 0; i < arr.Length - 1; i++)
            	{
            		int minIndex = i;
            		int minValue = arr[i];
            		for(int j = i + 1 ;j < arr.Length ;j++)
            		{
            			if(arr[j]<minValue)
            			{
            				minIndex = j;
            				minValue = arr[j];
            			}
            		}
            		arr[minIndex] = arr[i];
            		arr[i] = minValue;
            	}
            }
        }
    }
    

    内循环从第二个数开始和第一个数比较,在遍历一遍后找到最小的数,放到最左边


学习过程中参考了以下内容,诚挚感谢知识的分享者!

微软 | Microft docs(C# 编程指南)

菜鸟教程 | C# 教程

唐老狮 | C#四部曲

Suzkfly | C#随机数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睡不着乌托托

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值