博文

我学c++Builder系列(3)(2007-06-25 14:50:00)

摘要:三  C++ Builder中构件的属性 1.Align属性。 Align属性的取值 数值 说明 alBottom 构件与父窗口的底部对齐,例如状态条就与主窗口底部对齐alClient构件展开成填充父窗口客户区。如果客户区中有其它构件,则这构件填充客户区余下部分。例如Memo构件、Image构件和RichEdit构件 alLeft 构件与父窗口的左边对齐。例如垂直工具条就是个左对齐构件 alNone 构件按指定方法放置,与父窗口无特别关系,是大多数构件的缺省设置 alRight 构件与父窗口的右边对齐 alTop 构件与父窗口的顶边对齐,例如工具条就采用这种对齐方法   2.Name属性。 将构件放在窗体上时,C++ Builder在后台工作。C++ Builder所做的工作之一是生成构件的指针和赋予Name属性为变量名。例如,假设将Edit构件放在窗体上,并将其Name属性变为MyEdit。则C++Builder会在窗体头文件中放上下列语句:TEdit* MyEdit; C++ Builder在生成事件处理器名时也使用Name属性。假设要响应Edit构件的OnChange事件。通常,双击OnChange事件旁边的Value列,C++ Builder即会产生这个事件的事件处理器。C++ Builder根据构件的Name属性和所处理的事件生成缺省函数名。这里,C++ Builder生成函数MyEditChange()。 Name属性可以随时改变,但只能通过对象观察器改变。设计时改变构件Name属性时,C++ Builder遍历前面生成的所有代码,改变指针名和所有事件处理函数名。换句话说,C++ Builder会负责修改所写的代码,但你自己所写的代码要你自己修改和维护。一般来说,开始将构件放在窗体上时应改变Name属性,此后则保持不动。 警告:不要在运行时改变Name属性名,别在代码编辑器中手工改变构件名(C++ Builder指定的构件指针名)和事件处理器名,否则C++ Builder无法跟踪这些构件,结果肯定不理想,甚至无法装入窗体。Name属性只能通过对象观察器改变。 建议:尽快将构件Name属性从缺省名变为有意义的名称;运......

阅读全文(3824) | 评论:0

我学c++Builder系列(2)(2007-06-25 09:00:00)

摘要:二  C++ Builder中的菜单 菜单是大多数Windows程序的重要部分,有些Windows程序没有菜单,但大多数Windows程序都有。C++ Builder的菜单设计器使菜单设计非常方便。菜单设计器特性如下: 可以生成主菜单和弹出菜单。 可以立即访问代码编辑器,处理菜单项目的OnClick事件。 可以从模板或资源文件中插入菜单。 可以将自定义菜单存为模板。 菜单设计器的所有命令都可以通过菜单设计器弹出菜单或对象检查器访问。 在窗体中加进主菜单: 1. 先要在窗体中加进MainMenu构件,并将其Name属性变为MainMenu,注意MainMenu构件有几个属性,但没有事件,菜单的各个工作都在各个菜单项目中完成。        2. 双击MainMenu图标打开菜单设计器。        3. 从模板插入菜单。在菜单设计器中单击右键选择弹出菜单中的Insert From TempLate(从模版插入),Insert Template对话框显示了一列可以选择的模板,你可以选择自己需要的模版。这里我们要加进Edit菜单,所以选择Edit Menu并单击OK,菜单设计器中立即加进了整个Edit菜单。        4.加进Help菜单。单击Edit菜单右边的空白弹出菜单占位符,再次选择Insert From TempLate并插入Help菜单(但别选择ExpandedHelp Menu)。注意新菜单项目加入时,主窗体更新显示。        删除菜单项目:        生成Windows应用程序的过程是活的,很难一次性到位,而经常会出现需要更新菜单的情形。例如,前面插入的Edit菜单太长,其中有几个用不上的项目,所以要将其删除: 1.单击Edit菜单。 2.单击Repeat<command>项目。 3.按键盘上的Delete或选择菜单设计器弹出菜单中的Delete将其删除,这个项目即消失。 4.同法删除Pas......

阅读全文(2358) | 评论:0

我学c++Builder系列(1)(2007-06-18 07:45:00)

摘要:一  C++ Builder中的对话框 在C++ Builder中,对话框只是个窗体。生成对话框与生成主窗口窗体和其它窗体是一样的。为了防止缩放对话框,可以将BorderStyle属性变为bsDialog或bsSingle。 生成对话框: 1.       生成新窗体(单击工具条上的New Form按钮)。 2.       设置Name和Caption属性。例如将Name属性变为AboutBox,将Caption属性变为About Box。 3.       找到Caption属性上方的BorderStyle属性,将其变为bsDialog。 4.       然后给About框加进三个文本标题。编辑标题,即在Caption属性中输入文本。可以使用C++ Builder为文本标题的Name属性生成的缺省名。Name属性用不上,所以不需要具有说明意义的名称。 下面进行About框的修饰: 1.       找到构件板Additional标签中的Bevel按钮并单击它。 2.       移到窗体上,单击窗体并在三个文本标题周围拖动框。拖动停止时,出现Bevel构件,构件可以调整尺寸和位置。 3.       找到Shape属性并将其变为bsFrame,这样就在静态文本周围有了三维帧。 下面要在About框中加进图标: 1.       单击构件板上的Additional标签并选择Image构件,将构件放在窗体上文本左边。 2.       找到Image构件的AutoSize属性并将其变成true。 3.       找到Picture属性......

阅读全文(2634) | 评论:0

我所理解的指针和引用(2007-01-24 10:37:00)

摘要:指针和引用的对比 1.  指针存储的内容是其他对象(变量)的地址,使用指针来访问对象的成员函数和成员变量时,要使用“->”操作符;引用是对象(变量)的别名,使用引用来访问对象的成员函数和成员变量时,就像使用对象本身一样,使用“.”操作符。从这个角度来说,使用引用要比指针简洁得多。 2.  引用被创建的同时必须被初始化我们不能创建一个引用,过一会再初始化它(如果是类的话,在构造函数中使用初始化列表初始化);而指针则可以在任何时候被初始化。 3.  引用只能被初始化一次,一旦它们被初始化为一个特定的对象,它们就不能被改变了;指针则可以随时改变所指的对象。从这个意义上来说,引用像const的指针。 4.  不能有NULL引用,引用必须与合法的存储单元关联;指针则可以是NULL。 5.  引用不能像指针那样new或者delete,从这个意义上来说,它们像一个对象。 6.  当调用函数时,按引用或者指针传送比按值传送要节约一大比开支,同时允许改变实参。如果不允许改变实参,请将它们const。一个细微但是很明智的建议,当不允许函数改变某对象是,用const限定的引用就可以了,当需要改变的时候就用指针。 7.  一个好的原则是尽量使用引用,但有些情况下必须使用指针:如果一个对象需要动态创建或者销毁,应当使用指针。此外,指针可以改变指向的对象,指针可以为空,指针可以参与一些数学运算等,都是使用指针的理由。  ......

阅读全文(2492) | 评论:0

折半算法示例集锦之一(2006-12-06 22:56:00)

摘要:折半算法示例集锦
例1:计算x的N次方(N>=0)。 常规算法,复杂度为O(N):
double Power(double x, unsigned int N)
{
 double result = 1.0;
 for (unsigned int i=0; i<N; i++)
  result *= x;
 return result;
} 折半算法,复杂度为O(logN):
double Power(double x, unsigned int N)
{
 if (N == 0)
  return 1.0;
  
 double t = Power(x, N/2);
 if (N % 2 == 0)
  return t * t;
 else
  return t * t * x;
} 例2:静态查找问题,给定一个整数x和一个数组a,返回x在a中的下标,或者返回x不存在的标志。
如果x不止出现一次,则返回其中任意一个。
 若数组a未经过排序,则我们只能对数组进行线性顺序查找,复杂度为O(N):
template <typename T>
int OrderSearch(const vector<T> & a, const T & x)
{
 for (int i=a.size()-1; i>=0; i++)
 {
  if (a[i] == x)
   return i;
 }
 
 return NOT_FOUND; //NOT_FOUND = -1;
}
 若数组a已经经过排序,则我们可以使用折半查找,复杂度为O(logN):
template <typename T>
int Ord......

阅读全文(3856) | 评论:0

我所理解的动态内存分配(2006-11-23 16:34:00)

摘要:本文的内容大部分来自《C++Primer第三版中文版》,是我学习C++的一个笔记,写出来主要是作为初学者的一个参考,希望对大家有所帮助。        全局对象和局部对象的生命期是严格定义的,程序员不能够以任何方式改变它们的生命期。但是,有时候需要创建一些生命期能被程序员控制的对象,它们的分配和释放可以根据程序运行中的操作来决定。这种对象被称为动态分配的对象(dynamicaily allocated object)。动态分配的对象被分配在内存的堆中(有些资料称为自由空间(free store),其实就是堆)。关于堆的具体含义大家可以参考《数据结构》教程和文章《明晰C++内存分配的五种方法的区别》。 程序员用new表达式创建动态分配的对象,用delete表达式结束此类对象的生命期。动态分配的对象可以是单个对象,也可以是对象的数组,动态分配的数组的长度可以在运行时计算。        在本文中,我将向大家介绍我所理解的两种形式的new的表达式:一种支持单个对象的动态分配,另一种支持数组的动态分配。并详细分析一种智能指针auto_ptr。   一 单个对象的动态分配与释放        new表达式由关键字new及其后面的类型指示符构成。该类型指示符可以是内置类型或class类型。例如:                             new int ;        从堆中分配了一个int型的对象。类似地                     ......

阅读全文(3341) | 评论:0

我所理解的插入排序算法(2006-06-20 23:21:00)

摘要:插入排序是一种简单的排序方法,因为的实现比较简单,所以在数据量较少时应用很广泛。插入排序根据其插入的不同方式,可以分为直接插入排序,折半插入排序,2-路插入排序,表插入排序和希尔排序。在这里我将一一写出各种插入排序的算法代码。
直接插入排序
template <class T>
void InsertSort(T a[], int len)
{
      int i, j;
      T temp;
      for (i=1; i<len; i++)
      {
            temp = a[i];
            for (j=i-1; j>=0 && a[j]>temp; j--)//元素后移
                  a[j+1] = a[j];
            a[j+1] = temp;  //插入
      }......

阅读全文(3678) | 评论:0

我所理解的归并排序算法(2006-06-15 23:24:00)

摘要:归并排序算法以O(nlogn)最坏情形运行时间运行,而所使用的比较次数几乎是最优的。它可以用递归的形式实现,形式简洁易懂。但是需要注意的是当用递归形式时,如果数据较多,则开销很大,实用性很差,所以我们一般采用非递归的形式。我这里两种形式都给出。
      不管是递归还是非递归,归并排序算法中基本的操作是合并两个已经排序的数组。
递归形式:
template <class T>
void MSort(T a[], int left, int right)
{
      if (left < right)
      {
            int center = (left + right) / 2;
            MSort(a, left, center);
            MSort(a, center+1, right);
            Merge(a, left, center, right, right-left+1);
      }
}

temp......

阅读全文(2477) | 评论:0

我所理解的堆排序算法(2006-06-14 10:10:00)

摘要:我所理解的堆排序算法
      堆排序在最坏的情况下,其时间复杂度也能达到O(nlogn)。相对于快速排序来说,
这是它最大的优点,此外,堆排序仅需要一个记录大小供交换用的辅助存储空间。
      堆排序的数据结构是二叉堆,二叉堆的特点有两个,一个是它是一棵完全二叉树,
另一个是它的根结点小于孩子结点,所以我们很容易找到它的最小结点----根结点;当然
如果你想找到最大结点的话,那就要扫描所有的叶子结点,这是很费时间的,如果你想找的
是最大结点的话,你最好把它弄成一个大顶堆,即一棵根结点大于孩子结点的完全二叉树。
      二叉堆通常用数组来实现,它舍弃下标0,从下标1开始置数,则很容易满足,对于数组
中任意位置i上的元素,其左儿子的位置在2i上,右儿子的位置在2i+1上,双亲的位置则在
i/2上。
      堆排序的算法之一是把数组构建成二叉堆----这只要增添一个长度为n+1的辅助空间,
然后把原数组的元素依次插入到二叉堆即可。然后删除二叉堆的根,把它作为排序后的数组
的第一个元素,然后使二叉堆的长度减1,并通过上移使得新得到的序列仍为二叉堆,
再提取新二叉堆的第一个元素到新数组。依此类推,直到提取最后一个元素,
新得到的数组就是排序后的数组。
template <class T>
void Insert(T a[], int len, T x)//把x插入到原长度为len的二叉堆,注意保证新二叉堆不越界
{
      int i;
      for (i=len; i/2>0 && a[i/2]>x; i/=2)
            a[i] = a[i/2];
 &n......

阅读全文(4505) | 评论:0

我所理解的快速排序算法(2006-06-14 10:09:00)

摘要:我所理解的快速排序算法
      快速排序是在实践中最快的已知排序算法,它的平均运行时间是O(NlogN)。该算法
之所以特别快,主要是由于非常精练和高度优化的内部循环。在队列中寻找合适的枢点元素,
并按枢点元素划分序列,是快速排序算法的关键。
      为简单起见,我这里数组的第一个元素作为枢点元素,重新排列数组,使得枢点元素
之前的元素都小于枢点元素,而枢点元素之后的元素都大于或等于枢点元素。
      在这里我提供算法的两种实现:
第一种:
template <class T>
int Parttion(T a[], int low, int high)
{
      T x = a[low];       while (low < high)
      {
            while (low < high && a[high] >=  x)
                  high--;
            a[low] = a[high];             while (low < high && a[low] <  x)
  ......

阅读全文(4308) | 评论:1