一切福田,不離方寸,從心而覓,感無不通。

Category Archives: C#

面试题:一道冒泡算法笔试题的演进史

  给定N个整数,请使用冒泡算法按照从大到小的顺序排序 1.可对N个整数的某一段(连续的M整数)排序  2.要求具有一定的可测试性 3.C#语言  ——————-- 思路: 1.冒泡算法 2.针对部分排序 3.可测试性 先上一段最简单的代码实现冒泡算法--这里错误的使用了选择排序,请参看改进版本的修正 int[] list= new int[] {1, 2, 3, 4, 5};         for (int i=0;i<list.Length;i++)             for (int j=i+1;j<list.Length;j++)             {                                 if (list[i]<list[j])                 {                     int tmp=list[i];                     list[i]=list[j];                     list[j]=tmp;                 }             }         for (int i=0;i<list.Length;i++)             System.Console.Write("{0}\t",list[i]);         System.Console.WriteLine(""); 观看上述代码,有如下发现 1)行1,主要进行数据的初始化工作,准备数据  2)行2-11,主要实现冒泡排序算法 3)行12-14,主要是显示结果 4)行1-14,包含算法实现,调用,实现和使用糅合在一起 第一次改进: 1)数据初始化部分,其实属于调用部分,此时用的是数组,扩展性较差,这里改成List<int>,并将此步重构成函数 //初始化N个数据void Init(List<int> list,int count){    System.Random a=new Random();    for (int i=0;i<count;i++)        list.Add(a.Next(100));} 这里初始化数据,主要是减少人工干预,自动产生测试数据,实际生产过程中,是需要按照实际情况,选取一些比较特殊的数据作为测试数据的. 2)冒泡排序算法实现过程部分,也可以重构成函数 //实现冒泡算法——这里错误的使用了选择排序     void Bubble(List<int> list)     {                 for (int i=0;i<list.Count;i++)             for (int j=i+1;j<list.Count;j++)             {                                 if (list[i]<list[j])                 {                     int tmp=list[i];                     list[i]=list[j];                     list[j]=tmp;                 }             }         } 正确的冒泡排序为 void Bubble(List<int> list)     {         bool bFlag=false;         for (int i=0;i<list.Count;i++)         {             bFlag=false;             for(int j=list.Count-1-1 ;j>i-1;j--)             {                 if (list[j]<list[j+1])                 {                     int tmp=list[j+1];                     list[j+1]=list[j];                     list[j]=tmp;                     bFlag=true;                 }             }             if (!bFlag) break;         }     }     将排序的代码,重构成函数,使得算法可以非常容易进行测试,只需要将精心设计的测试数据传给函数,就可以了 3)显示结果,也是重构成函数 //显示结果 void Print(List<int> list) {     for (int i=0;i<list.Count;i++)         System.Console.Write("{0}\t",list[i]);     System.Console.WriteLine(""); } 4)最终调用过程 public static void Main(){    List<int> list=new List<int>();    //产生测试数据    Init(list,8);        //打印测试数据    Print(list);        //按照从大到小的顺序排序    Bubble(list);    //打印排序后的结果    Print(list);    }  第二次改进: 第一次改进中,基本解决冒泡算法和可测试性的问题,但是还有一个重要问题没有解决,就是针对N个整数中的某一段连续M个数据进行排序,所以这次的改进主要集中在<冒泡排序算法实现>函数的改进 很明显,要实现这个功能,只需要,在 Bubble这个函数增加两个参数,标识出M的上下限,Bubble变成如下形式

新的实现(注意,这里我的冒泡算法的实现是不对的,我用的是选择排序,经过一个园子里的兄弟提醒,我查过资料,发现的确用错了) 选择排序(Selection sort) 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。 void Bubble(List<int> list,int low,int high){    int iHigh= list.Count<high+1? list.Count : high+1 ;    int iLow=low<0? 0 :low ;    //System.Console.WriteLine("{0}\t{1}",iLow,iHigh);    for (int i=iLow;i<iHigh;i++)        for (int j=i+1;j<iHigh;j++)        {                            if (list[i]<list[j])//比较不一定相邻            {                int tmp=list[i];                list[i]=list[j];                list[j]=tmp;            }        }    } 下面是更正后的冒泡排序代码 冒泡排序(BubbleSort) 依次比较相邻的两个数,将小数放在前面,大数放在后面。 static void Bubble(List<int> list,int low,int high)     {         int iHigh= list.Count<high+1? list.Count : high+1 ;         int iLow=low<0? 0 :low ;                  bool bFlag=false;         for (int i=iLow;i<iHigh;i++)         {             bFlag=false;             for(int j=iHigh-1-1 ;j>i-1;j--)             {                 if (list[j]<list[j+1])//比较相邻                 {                     int tmp=list[j+1];                     list[j+1]=list[j];                     list[j]=tmp;                     bFlag=true;                 }             }             if (!bFlag) break;         }         }   并提供一个重载函数

调用: public static void Main() {     List<int> list=new List<int>();     //产生测试数据     Init(list,8);         //打印测试数据     Print(list);         //按照从大到小的顺序排序,针对序号2-5的之间的数据     Bubble(list,2,5);     //打印排序后的结果     Print(list);  } 至此,题目要求的目的全部达到,不过还是少了点什么,下面进行第三次改进 第三次改进: 第一次改进和第二次改进的结果,还是采用面向过程的方法,第三次改进侧重与面向对象的方法,就是封装 三个主要函数中都有List<int> list参数,这个是主要数据,我们用类来封装它,如下给出完整代码 public class BubbleSort {     List<int> _list;     public BubbleSort()     {         _list=new List<int>();     }     public BubbleSort(List<int> list)     {         _list=list;     }          public void Sort()     {                 Sort(    _list,0,_list.Count-1);             }         public void Sort(int low,int high)     {         Sort(    _list,low,high);     }     //实现冒泡算法--这里错误使用选择排序,请替换为第二次改进中的正确实现      public void Sort(List<int> list,int low,int high)     {         //int iHigh= list.Count<low+count? list.Count : high ;         int iHigh= list.Count<high+1? list.Count : high+1 ;         int iLow=low<0? 0 :low ;         //System.Console.WriteLine("{0}\t{1}",iLow,iHigh);         for    (int i=iLow;i<iHigh;i++)             for    (int j=i+1;j<iHigh;j++)             {                                 if (list[i]<list[j])                 {                     int tmp=list[i];                     list[i]=list[j];                     list[j]=tmp;                 }             }         }                  //初始化N个数据     public void Init(int count)     {         _list.Clear();         System.Random a=new Random();         for    (int i=0;i<count;i++)             _list.Add(a.Next(100));     }     //显示结果     public  void Print(List<int> list)     {         Print(list,0,list.Count-1,true);     }     public  void Print(List<int> list,int low,int high,bool IsNewLine)     {         int iHigh= list.Count<high+1? list.Count : high+1 ;         int iLow=low<0? 0 :low ;                  for    (int i=iLow;i<iHigh;i++)             System.Console.Write("{0}\t",list[i]);         if (IsNewLine)             System.Console.WriteLine("");     }     public void Print(int low,int high,bool IsNewLine)     {         Print(_list,low,high,IsNewLine);     }     //将排序的M个数据用红色显示     public void Print(int low,int high)     {         Print(0,low-1,false);         System.Console.ForegroundColor=ConsoleColor.Red;         Print(low,high,false);                 System.Console.ResetColor();         Print(high+1,_list.Count,true);     }          public void Print()     {         Print(_list);     }     //for test     public void Test()     {         //产生测试数据         Init(10);             //打印测试数据         Print();             //按照从大到小的顺序排序         int[] iLowHigh=new int[]{4,7};         Sort(iLowHigh[0],iLowHigh[1]);         //Sort(-1,8);         //Sort(0,18);         //Sort(-1,18);         //打印排序后的结果         //Print();          Print(iLowHigh[0],iLowHigh[1]);          } } 调用代码:

 

龙生   20 Nov 2012
View Details

C#操作注册服务卸载服务启动服务停止服务

   

龙生   25 Oct 2012
View Details

线程间操作无效: 从不是创建控件“label1”的线程访问它

Thread thread=null; //定义线程  //开始线程   private void button1_Click(object sender, EventArgs e)   {   thread = new Thread(new ThreadStart(StartThread));   thread.Start();//开始线程   }   private void StartThread()   {   int i = 0;   while (true)   {   this.label1.Text = i.ToString(); //此处报错   i++;   }   }   //结束线程   private void button4_Click(object sender, EventArgs e)   {   thread.Abort();   }   问题:当我们运行的时候会出现错误:"线程间操作无效: 从不是创建控件“label1”的线程访问它。" 解决方案:在程序运行的时候增加一句话,如下: public Form1() {InitializeComponent();Control.CheckForIllegalCrossThreadCalls = false; //这是增加的一句话 }  缺点:将UI传给了子线程,违背了弱耦合、封装的思想。子线程去更新UI的状态,如果有多个不同主线程要获取子线程状态,怎么办?   

龙生   22 Oct 2012
View Details

C#进制转换

 

龙生   15 Oct 2012
View Details

C# 知识点 goto【学习笔记】

 定义

备注

可以考虑使用goto的情形 

不加限制地使用goto带来的弊端

示例 goto 在 switch 语句中的使用。

示例输出

使用 goto 跳出嵌套循环

龙生   24 Sep 2012
View Details

C#的Escape和Unescape

基于C#的Escape和Unescape实现 //在C#后台实现JavaScript的函数escape()的字符串转换//些方法支持汉字private string escape(string s){StringBuilder sb = new StringBuilder();byte[] byteArr = System.Text.Encoding.Unicode.GetBytes(s); for (int i = 0; i < byteArr.Length; i += 2){ sb.Append("%u");sb.Append(byteArr[i + 1].ToString("X2"));//把字节转换为十六进制的字符串表现形式 sb.Append(byteArr[i].ToString("X2"));}return sb.ToString(); }//把JavaScript的escape()转换过去的字符串解释回来//些方法支持汉字private string unescape(string s){ string str = s.Remove(0, 2);//删除最前面两个"%u"string[] strArr = str.Split(new string[]{"%u"}, StringSplitOptions.None);//以子字符串"%u"分隔byte[] byteArr = new byte[strArr.Length * 2];for (int i = 0,j=0; i < strArr.Length;i++,j+=2){byteArr[j + 1] = Convert.ToByte(strArr[i].Substring(0,2), 16); //把十六进制形式的字串符串转换为二进制字节byteArr[j ] = Convert.ToByte(strArr[i].Substring(2, 2), 16);}str = System.Text.Encoding.Unicode.GetString(byteArr); //把字节转为unicode编码return str; }   下面的为不支持汉字的转换: public static string Escape(string str){if (str == null)returnString.Empty; StringBuilder sb = newStringBuilder();int len = str.Length; for […]

龙生   21 Sep 2012
View Details

贴一下聚合函数在LinQ to Object和LinQ to DataSet中的用法

     var member = new Member();             int recordCount;             var memberInfos = member.Paging(20, 1, "MemberId DESC", "", out recordCount);             var memberIdSum = memberInfos.Sum(c => c.MemberId);             Response.Write(memberIdSum.ToString());             Response.Write("<br/>——————————————————-<br />");               var dbHelper = DbFactory.AccessSqlServer;             var dbPaging = DBPaging.Create(dbHelper);             var ds = […]

龙生   11 Sep 2012
View Details

LINQ TO DataSet Overview

 相对而言,LINQ TO DataSet是LINQ技术中最小的一块,虽然是DB中抽取出来的一个离线的操作模型,但毕竟对象也是个内存里面的object而已。所以和LINQ TO Object相比,大多数的操作都是一样的,不同只是要根据DataSet,DataTable的结构标明字段而已。下面简单的列出LINQ TO DataSet相比LINQ TO Object一些要注意的特色。   Query UnTyped DataSet   和一般的LINQ相比,query对象是untyped DataSet的时候,使用Field<T>和SetField<T>来读写不同的column字段,下面是一个简单的例子:   DataTable orders = ds.Tables["Orders"]; DataTable orderDetails = ds.Tables["OrderDetails"];   var query =     from    o in orders.AsEnumerable()     where   o.Field<DateTime>( "OrderDate" ).Year >= 1998     orderby o.Field<DateTime>( "OrderDate" ) descending     select  o;   在这里大致要注意三点 1.因为untyped DataSet没有实现IEnumerable<T> 和 IQueryable<T>的interface,所以如果想把它作为一个可以查询的对象的话,要先用AsEnumerable() 或者AsQueryable()转换一下,将它转换成IEnumerable<T>或者IQueryable<T>对象才能用LINQ去查询。如:from o in orders.AsEnumerable()   2.一般是使用使用Field<T>(“Column A”)和SetField<T>(“Column A”)来读写不同的column字段对应的element,用它来访问相对于以前我们用ds.Tables["Orders"].Row[“RowA”][ “Column A”]的访问模式比起来,一个很大的好处就是可以避免null类型产生的exception。我们以前从DataSet里面取数据的时候,如果取的出来的是null,就会抛出exception,所以我们经常作类似if(ds.Tables["Orders"].Row[“RowA”][ “Column A”]!=null)的判断来包装我们进一步的逻辑处理,但是用Field<T>(“Column A”)就可以避免这种麻烦。因为Field<T>(“Column A”)是nullable的。这个特性的由来是<T>这个泛型的使用,比如你取int类型数据的时候,如果你觉得它可能是null,那你就可以用Field<int?>(“Column A”)去取,这样就可以避免了exception的抛出。   3 .Field<T>和SetField<T>是使用并不局限在LINQ 的query当中,在程序的其他地方也能使用,可以用它去替代以前的我们访问DataSet的方式,例如:  

    Query Typed DataSet   这就更加简单了。对于定义了类型的DataSet,我们可以象查询内存中一般的object那样去查询它。例如:  

  还有一个与untyped DataSet不同的地方是在查询它的时候不需要使用AsEnumerable() 或者AsQueryable()那样的转换方法了。因为所有定义好的DataSet都是继承了TypedTableBase<T>这个基类,而这个基类已经实现了IEnumerable<T>的interface     Query DataSet中的relation   DataSet当中有时候也是有relation的,和DB一样,例如在下面的DataSet中加入relation:  

  如果我们想像在LINQ […]

龙生   11 Sep 2012
View Details

Linq to DataSet

1.数据集( DataSet )   • DataSet 是更为广泛使用的ADO.NET 组件之一,它可以显式缓存不同数据源中的数据。   • 在表示层上DataSet 与GUI 控件紧密集成,以进行数据绑定。   • 在中间层上,它提供保留数据关系形状的缓存并包括快速简单查询和层次结构导航服务,从而可以减少对数据库的请求数。 2.查询数据集   • DataSet 虽然具有突出的优点,但其查询功能也存在限制。   • Select  方法可用于筛选和排序,GetChildRows和GetParentRow 方法可用于层次结构导航。   • 但对于更复杂的情况,开发人员必须编写自定义查询。这会使应用程序性能低下并且难以维护。 3.使用LINQ to DataSet   • 使用LINQ to DataSet 可以更快更容易地查询在DataSet 对象中缓存的数据。   • 这些查询用编程语言本身表示,而不表示为嵌入在应用程序代码中的字符串。   • LINQ to DataSet 可使Visual Studio 开发人员的工作效率更高,     因为Visual Studio IDE 提供编译时语法检查、静态类型化和对 LINQ  的智能感知的支持。   • LINQ to DataSet 也可用于查询从一个或多个数据源合并的数据 这可以使许多需要灵活表示和处理数据的方案能够实现。 4.查询数据集    • 填充DataSet     – XxxDataAdapter     – LINQ to SQL    •主要使用下面两个扩展类     – DataRowExtensions     – DataTableExtensions   • 查询支持     – 类型化数据集     – 非类型化数据集 5.启用LINQ to DataSet 功能    • 要求.NET Framework 3.5   • 引用System Data DataSetExtensions 程序集 […]

龙生   11 Sep 2012
View Details

LinQ&EF任我行(一)--LinQ to SQL (转)

LinQ家族五大成员:LinQ to Objects – 默认功能,用来实现对内存中集合对象的查询LinQ to SQL – 针对SQL Server的查询,它是一个带有可视化的操作界面的ORM工具LinQ to DataSet – 对强类型化或弱类型化的DataSet或独立的DataTable进行查询LinQ to Entity – 对实体框架中EDM定义的实体集合进行查询。LinQ to XML – 对XML文档进行查询创建等操作。 C#语法与LinQ相关的新增功能 1.隐式强类型变量在C#3.0中可以使用var关键字隐式定义强类型局部变量。 《图1》这里的var关键字定义变量与JavaScript定义变量看起来很像但二者有着本质的区别。JavaScript定义的变量是弱类型的变量,也可理解为是一种通用类型的变量,它可以容纳各种类型的值,还可以在运行过程中动态修改其中的内容类型。下面这种写法在JavaScript中是正确的:var obj = 3.14;obj = "hello world";C#中的var则是种强类型的变量,它在定义的时候会确定数据类型,分配内存空间。上面这两名代码在C#3.0中会报错,因为第一句已经把obj定义为double型的变量,第二句把字符串赋值给double是错误的操作。 隐式强类型并不能有效简化我的书写的代码,但当我们在用它来动态接收一些未知类型的数据的时候就显虽得很强大。在隐式强类型变量出现前,我们一般是使用object型变量来接收这种未知类型的数据的。 2.对象初始化这个功能可以有效简化类的getter和setter部份的代码,还可以只使用一行表达式语句实现对象的实例化与初始化操作。如定义实例类时可以使用如下代码,没有必要再把成员变量和属性分别定义了。public class LineItem{    public int OrderID { get; set; }    public int ProductID { get; set; }    public short Quantity { get; set; }    public string QuantityPerUnit { get; set; }    public decimal UnitPrice { get; set; }    public float Discount { get; set; }} 实例化LineItem对象,并为它赋值var line3 = new LineItem { OrderID = 11000, ProductID = 61, Quantity = […]

龙生   11 Sep 2012
View Details
1 36 37 38 43