搜索
bottom↓
回复: 11

从顺序表的算法看指针的妙用

[复制链接]

出0入0汤圆

发表于 2011-1-20 16:36:59 | 显示全部楼层 |阅读模式
科学的发现往往是偶然的,我在研究算法的时候,发现了C语言指针的另类用法,技巧令人拍案叫绝,欲知详情,请看下文。

首先,先看一下下面的这段代码:

//定义顺序表的元素类型。应根据需要修改
typedef int DataType;
struct SeqList
{  int   MAXNUM;       //顺序表中最大元素的个数
   int      n;       //存放线性表中元素的个数n≤MAXNUM  
   DataType *element; //element[0],element[1],…,element[n - 1]存放//线性表中的元素
};

这段代码摘自张乃孝《算法与数据结构》一书。
很明显,这是用顺序表示的线性表的数据结构,其中DataType *element这一行代码的含义开始的时候自己是看不懂的,觉得弄那么复杂干啥?后来经过再三的分析,终于明白了。
它的含义:定义一个指向DataType类型的指针变量,实质是利用了指针可以引用(表示)一个数组首地址的性质,所以这里实际上相当于定义了一个数组的首地址,但这个数组没有定义它的大小。后面要用数组来存放数据时只要用element[0],element[1]……表示即可。
我个人是非常佩服这样的算法技巧,相当巧妙。为了做对比,我就把目前主流的顺序表数据结构的定义算法放上来。代码如下:

顺序表类型定义
  #define ListSize 100 //表空间的大小可根据实际需要而定,这里假设为100
  typedef int DataType; //DataType的类型可根据实际情况而定,这里假设为int
  struct  SeqList{
      DataType data[ListSize];//向量data用于存放表结点
      int length;//当前的表长度
     };

看出了吧,这里都是直接在初始化时把数据存放的空间定死了,就是ListSize 100个DataType数据的空间。
下面对这两段代码做一个比较。
第一种用指针来实现数组的定义,它可以在程序的运行中根据程序的需要,例如根据用户输入的数据量m,一次性定义一个可以存放m个数据的空间。第二种的方法直接在程序代码中限制死了空间的大小,由于很多时候人们为了考虑出现数据量大的情况,所以一般这个空间设置得比较大,这样容易导致内存空间的浪费。
读者可能会问,这样又有什么作用?
可能对于现在的计算机来说,内存已经是很大的了,省这一点空间没有什么的。但我想说的是,假如用在内存资源奇缺的单片机上呢?用在小内存的手机上呢?例如51单片机的内存空间才是512B,这样的情况下,省一点空间就是效率。况且对于算法来说,高效率而占用空间小永远是它的改进方向。
或者有人会说,不用指针,直接定义一个数组DataType element[m],其中的m的值通过程序运行时再给定。其实,我很遗憾的告诉你,绝大多数的编译器对于数组定义时候,一定要给出一个确定值的,这样的语法是有问题的,所以还是建议你搞好C语言的基础再说吧。

除了上面的不同外,还有一点是他们的创建表的操作也是不一样的。
对于第二种来说,十分简单,创建的代码只用一句就行了:
struct  SeqList  Seq
但对于第一种来说,多了一个动态分配空间的过程,代码如下:

PSeqList createNullList_seq(int m ) {
// 创建新的顺序表
    PSeqList palist = (PSeqList)malloc(sizeof(struct SeqList));
  if (palist!=NULL){
     palist->element = (DataType*)malloc(sizeof(DataType)*m);
    if (palist->element){
       palist->MAXNUM=m;
       palist ->n = 0;                // 空表长度为0
       return (palist);
      }
       else free (palist);
    }
    printf(“Out of space!!\n”);    // 存储分配失败
    return NULL;
}
代码的含义是根据需要来创建一个可以存放m个DataType数据类型的数据空间。核心代码是palist->element = (DataType*)malloc(sizeof(DataType)*m);
没看懂的好好体会一下。

通过以上这两种算法的分析,再一次见证了指针的威力,不愧为C语言的精髓所在!希望这种指针的用法可以对大家有所启示,以后可以通过它来提高程序执行效率和通用性。

出0入0汤圆

发表于 2011-1-20 17:08:08 | 显示全部楼层
这种很常用的。。。。类似还有
struct {
    int n;
    char array[0];    //[0]编译不过去也可写成1
}
用途各异。

出0入0汤圆

发表于 2011-1-20 22:59:07 | 显示全部楼层
弱弱问下,malloc()在51上怎么实现?
================================================================
数组越界虽然C语言标准规定不进行检查,但是编译器有可能给出Warning



“或者有人会说,不用指针,直接定义一个数组DataType element[m],其中的m的值通过程序运行时再给定。其实,我很遗憾的告诉你,绝大多数的编译器对于数组定义时候,一定要给出一个确定值的,这样的语法是有问题的,所以还是建议你搞好C语言的基础再说吧。 ”

C99标准支持可变长度数组,DataType element[m]是可以编译出来的,51的编译器估计是不支持

出0入0汤圆

发表于 2011-1-20 23:47:41 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-1-21 08:53:45 | 显示全部楼层
楼主在研究《数据结构》吗?

出0入0汤圆

发表于 2011-1-21 09:50:06 | 显示全部楼层
一个是事先分配内存,一个是动态分配内存。用途各异。

不过指针真的是C语言中最强大的工具,善加利用,好处多多啊。当然使用不当的话,也会把自己搞糊涂。

就像一把利剑,既能战斗,也可能自残。

出0入4汤圆

发表于 2011-1-21 10:00:37 | 显示全部楼层
PASCAL的指针也很强大

出0入0汤圆

发表于 2011-1-21 11:11:24 | 显示全部楼层
受教了!

出0入0汤圆

发表于 2011-1-21 15:49:13 | 显示全部楼层
留个记号!

出0入0汤圆

发表于 2011-1-21 20:05:08 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-4-16 00:46:33 | 显示全部楼层
没看到有多高级

出0入0汤圆

发表于 2011-4-16 05:19:53 | 显示全部楼层
同样对于malloc()在51上的实现感到困惑  不知哪位大侠可以指点一下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-6 12:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表