链栈简单实例:括号匹配,表达式运算

软件和网站开发以及相关技术探讨
回复
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

链栈简单实例:括号匹配,表达式运算

#1

帖子 flyinflash » 2008-06-11 20:38

代码: 全选

//  Linked Stack Example | Match Brackets

//  Last Modified: 2008-06-10
//  Last Modified: 2008-06-11

#include <stdio.h>
#include <stdlib.h>


typedef struct node
{
  char data;
  struct node *next;
} stack;


stack *init(stack *top)
{
  stack *tmp;

  while (top->next)
  {
    tmp = (stack *)malloc(sizeof(stack));
    tmp = top;
    top = top->next;
    free(tmp);
  }
  printf("\n");
  printf("\n\n :: init stack :: ");

  return top;
}


int is_empty(stack *top, int print_msg)
{
  if (top->data)
  {
    if (print_msg) printf("\n\n stack is not empty ");
    return 0;
  }
  else
  {
    if (print_msg) printf("\n\n stack is empty ");
    return 1;
  }
}


void print(stack *top)
{
  stack *tmp;
  tmp = (stack *)malloc(sizeof(stack));

  if (!is_empty(top, 0))
  {
    tmp = top;
    printf("\n\n  +---+ ");
    while (tmp && tmp->data)
    {
      printf("\n  | %c | ", tmp->data);
      printf("\n  +---+ ");
      tmp = tmp->next;
    }
  }
}


stack *push(stack *top, char val)
{
  stack *tmp;
  tmp = (stack *)malloc(sizeof(stack));

  if (!tmp)
  {
    printf("\n\n  overflow ");
    return top;
  }

  //if (val > 33 && val > 126)
  //  val = 129;

  tmp->data = val;
  tmp->next = top;
  top = tmp;

  return top;
}


stack *pop(stack *top)
{
  stack *tmp;
  tmp = (stack *)malloc(sizeof(stack));

  if (is_empty(top, 0))
    return top;

  tmp = top;
  top = top->next;
  free(tmp);

  return top;
}


char get_top(stack *top)
{
  if (is_empty(top, 0))
    return '\0';

  return top->data;
}


int main()
{
  stack *init(stack *top);

  stack *push(stack *top, char val);
  stack *pop(stack *top);
  char get_top(stack *top);
  int is_empty(stack *top, int print_msg);

  void print(stack *top);

  char keys[512];
  int i;

  stack *top = (stack *)malloc(sizeof(stack));


  printf("\n\n  Linked Stack Example | Match Brackets ");

  while (1)
  {
    printf("\n\n input '#' to quit ");
    printf("\n brackets: ");
    scanf("%s", keys);

    for (i = 0; keys[i]; i++)
    {
      switch(keys[i])
      {
        case '{':
        case '[':
        case '(':
          top = push(top, keys[i]);
          break;

        case '}':
          if (!is_empty(top, 0) && (get_top(top) == '{'))
          {
            top = pop(top);
            break;
          }
          else goto QUIT_FLAG;

        case ']':
          if (!is_empty(top, 0) && (get_top(top) == '['))
          {
            top = pop(top);
            break;
          }
          else goto QUIT_FLAG;

        case ')':
          if (!is_empty(top, 0) && (get_top(top) == '('))
          {
            top = pop(top);
            break;
          }
          else goto QUIT_FLAG;

        case '#':
          return 0;
          break;
      }
    }

    if (is_empty(top, 0))
    {
      printf("\n\n  MATCH ");
    }
    else
    {
      QUIT_FLAG:
      print(top);
      printf("\n\n  don't match ");
    }
    top = init(top);
  }

  return 0;
}
上次由 flyinflash 在 2008-06-12 0:18,总共编辑 1 次。
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
联系:

#2

帖子 BigSnake.NET » 2008-06-11 20:40

写个表达式运算吧..
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#3

帖子 flyinflash » 2008-06-12 0:16

代码: 全选

/*     组长: %!@()*%
 *     组员: *$!@#)(%!
 */

#include <stdio.h>
#include <stdlib.h>

char *head;
typedef struct node1
{
  float value;
  struct node1 *next;
}ValueStack;
ValueStack *vtop=NULL;

typedef struct node2
{
  char oper;
  struct node2 *next;
}OperStack;
OperStack *otop=NULL;

void Input()
{
  char ch,*p;
  int i,j;
  p=head=(char *)malloc(sizeof(char)*20);
  printf("Please input(input 'q' to exit):\n");
  ch=getchar();
  if( ch=='q' )
  {
    exit(0);
  }
  for(i=0,j=0; ch!='\n'; i++)
  {
    *(p++)=ch;
    if(19==i)   /* 前面申请的空间已满 */
    {
      head=(char *)realloc(head,20+(++j)*20);
      p=head+20*j;
      i=-1;
    }
    ch=getchar();
  }
  *p='#';
}

/* 检查表达式是否正确 */
int Examine()
{
  void PushOper(char),PopOper();
  char *p=head;
  int n;

  while(*p!='#')
  {
    if( '0'<=*p && *p<='9' )   /* 当p指向数值 */
    {
      n=0;
    }
    else if( *p=='+' || *p=='*' || *p=='-' || *p=='/' )   /* 当p指向运算符 */
    {
      if( n!=1 )
      {
        n=1;
      }
      else
      {
        printf("Error,");
        return 0;
      }
    }
    else if( *p!='(' && *p!=')' )   /* 表达式有非法字符 */
    {
      printf("Error,");
      return 0;
    }

    switch(*p)
    {
      case '(':
        PushOper(*p);
        break;
      case ')':
        if( otop!=NULL )    /* 栈不空即栈顶有字符'(' */
        {
          PopOper();
        }
        else
        {
          printf("The bracket does not match,");
          return 0;
        }
    }
    p++;
  }

  if( otop!=NULL )
  {
    printf("The bracket does not match,");
    return 0;
  }
  else
  {
    return 1;
  }
}

 /* 将字符转化为数值 */
float CharToValue(char *p)
{
  char str[5];
  int i,j,k,n;
  float value=0;
  for(i=0; '0'<=*p && *p<='9'; i++)
  {
    str[i]=*p;
    p++;
  }
  for(j=0;j<i;j++)
  {
    n=str[j]-48;
    for(k=1; k<(i-j); k++)
        n*=10;
    value+=n;
  }
  return value;
}

/* 找下一个数值或运算符 */
char *FindNext(char *p)
{

  /* 找下一个数值 */
  if('0'<=*p && *p<='9')
  {
    while('0'<=*p && *p<='9')
      p++;
    while((*p<'0' || *p>'9') && *p!='#')
      p++;
  }
  /* 找下一个运算符 */
  else
  {
    for(p++; '0'<=*p && *p<='9'; p++)
      ;
  }
  return p;
}

/* 判断优先级 */
char FirstOrLater(char oper1,char oper2)
{
    static char OperList[6][8]={' ','+','-','*','/','(',')','#',
                                '+','0','0','1','1','1','0','0',
                                '-','0','0','1','1','1','0','0',
                                '*','0','0','0','0','1','0','0',
                                '/','0','0','0','0','1','0','0',
                                '(','2','2','2','2','2','3',' '};   //'#'为表达式的结束标志
  int i,j;
  for(i=1; OperList[i][0]!=oper1; i++)
    ;
  for(j=1; OperList[0][j]!=oper2; j++)
    ;
  return OperList[i][j];
}

float BasicCalcul(float x,float y,char oper)
{
  switch(oper)
  {
    case'*': return x*y;
    case'/': return x/y;
    case'+': return x+y;
    case'-': return x-y;
  }
}

/* 将数值压入栈 */
void PushValue(float val)
{
  ValueStack *p;
  p=(ValueStack *)malloc(sizeof(ValueStack));
  p->value=val;
  p->next=vtop;
  vtop=p;
}

/* 将运算符压入栈 */
void PushOper(char oper)
{
  OperStack *p;
  p=(OperStack *)malloc(sizeof(OperStack));
  p->oper=oper;
  p->next=otop;
  otop=p;
}

/* 数值出栈 */
void PopVal()
{
  ValueStack *p;
  p=vtop;
  vtop=vtop->next;
  free(p);
}

/* 运算符出栈 */
void PopOper()
{
  OperStack *p;
  p=otop;
  otop=otop->next;
  free(p);
}

float Calculate()
{
  char *pv=head,*po=head,oper,ch1;
  float value[2];

  /* pv指向存储数字的单元,po指向存储运算符的单元 */
  while('0'>*pv || *pv>'9')
    pv++;
  while('0'<=*po && *po<='9')
    po++;

  value[0]=CharToValue(pv);
  pv=FindNext(pv);
  value[1]=CharToValue(pv);
  pv=FindNext(pv);
  oper=*po;
  po=FindNext(po);
  ch1=FirstOrLater(oper,*po);

  while(oper!='#')    /* '#'为表达式的结束标志  */
  {
    /* 判断优先级并做相应操作 */
    if('0'==ch1)
    {
      value[0]=BasicCalcul(value[0],value[1],oper);
    }
    else if('1'==ch1)
    {
      PushValue(value[0]);
      PushOper(oper);
      value[0]=value[1];
      value[1]=CharToValue(pv);
      pv=FindNext(pv);
      oper=*po;
      po=FindNext(po);
      ch1=FirstOrLater(oper,*po);
      continue;
    }
    else if('2'==ch1)
    {
      PushOper(oper);
      oper=*po;
      po=FindNext(po);
      ch1=FirstOrLater(oper,*po);
      continue;
    }
    else
    {
      PopOper();
      po=FindNext(po);
    }

    if(otop!=NULL)   /* 运算符栈中有运算符 */
    {
      oper=otop->oper;
      ch1=FirstOrLater(oper,*po);
      if('0'==ch1)
      {
        value[1]=value[0];
        value[0]=vtop->value;
        PopVal();
        PopOper();
        continue;
      }
      else if('3'==ch1)
      {
        continue;
      }
    }
    if((oper=*po) == '#')
    {
      return value[0];
    }
    po=FindNext(po);
    value[1]=CharToValue(pv);
    pv=FindNext(pv);
    ch1=FirstOrLater(oper,*po);
  }
  return value[0];
}

int main()
{
  while(1)
  {
    do
    {
        Input();
        otop=NULL;   /* 将运算符栈置空 */
      }while( Examine()==0 );
      printf("Output: %f\n",Calculate());
    }
    return 0;
}
上面这个不是我写的,舍友写的。
这个舍友是众多会友里面唯一使用 Linux 的人,虽然它不明白什么是 GNU,什么是 Linux ,不过,它觉得 Geany 不错。

个人觉得代码风格比较丑陋。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#4

帖子 flyinflash » 2008-06-12 0:20

小猫,记住,上大学后不要逃专业课。不然您就会像我现在这样,补啊补,追啊追。该死的考试。
上次由 flyinflash 在 2008-06-12 13:12,总共编辑 1 次。
头像
tscmga
帖子: 274
注册时间: 2008-03-16 23:09

#5

帖子 tscmga » 2008-06-12 3:04

Rule of Representation: Fold knowledge into data, so program logic can be stupid and robust.

Even the simplest procedural logic is hard for humans to verify, but quite complex data structures are fairly easy to model and reason about. To see this, compare the expressiveness and explanatory power of a diagram of (say) a fifty-node pointer tree with a flowchart of a fifty-line program. Or, compare an array initializer expressing a conversion table with an equivalent switch statement. The difference in transparency and clarity is dramatic. See Rob Pike's Rule 5.

Data is more tractable than program logic. It follows that where you see a choice between complexity in data structures and complexity in code, choose the former. More: in evolving a design, you should actively seek ways to shift complexity from code to data.

The Unix community did not originate this insight, but a lot of Unix code displays its influence. The C language's facility at manipulating pointers, in particular, has encouraged the use of dynamically-modified reference structures at all levels of coding from the kernel upward. Simple pointer chases in such structures frequently do duties that implementations in other languages would instead have to embody in more elaborate procedures.

(We also cover these techniques in Chapter 9.)

这段代码可以用unix的方法把逻辑变成数据。这样代码更短。

map { { ,push
[,push
( ,push
) , ....
}

while(p++){
map[p](...);
}

代码: 全选

    for (i = 0; keys[i]; i++)
    {
      switch(keys[i])
      {
        case '{':
        case '[':
        case '(':
          top = push(top, keys[i]);
          break;

        case '}':
          if (!is_empty(top, 0) && (get_top(top) == '{'))
          {
            top = pop(top);
            break;
          }
          else goto QUIT_FLAG;

        case ']':
          if (!is_empty(top, 0) && (get_top(top) == '['))
          {
            top = pop(top);
            break;
          }
          else goto QUIT_FLAG;

        case ')':
          if (!is_empty(top, 0) && (get_top(top) == '('))
          {
            top = pop(top);
            break;
          }
          else goto QUIT_FLAG;

        case '#':
          return 0;
          break;
      }
    } 
头像
tscmga
帖子: 274
注册时间: 2008-03-16 23:09

#6

帖子 tscmga » 2008-06-12 3:13

unix哲学里倡导的是简单,清晰。好像按这个标准来说,楼主的代码比你舍友的要好N倍。我一下子就看明白了。你舍友的我没看明白。如果我用和一个程序在一起做的话,我更喜欢楼主这样的。
实际上面要做到简单清晰要有很清楚的思路,有时候还要经验。就是做复杂过一次,等二次做才能简单。

不过你舍友的实现的功能多,如果是仅仅完成你的那些功能,他的代码比你的更专业。哈哈


More of the Unix philosophy was implied not by what these elders said but by what they did and the example Unix itself set. Looking at the whole, we can abstract the following ideas:

1.

Rule of Modularity: Write simple parts connected by clean interfaces.
2.

Rule of Clarity: Clarity is better than cleverness.
3.

Rule of Composition: Design programs to be connected to other programs.
4.

Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
5.

Rule of Simplicity: Design for simplicity; add complexity only where you must.
6.

Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
7.

Rule of Transparency: Design for visibility to make inspection and debugging easier.
8.

Rule of Robustness: Robustness is the child of transparency and simplicity.
9.

Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
10.

Rule of Least Surprise: In interface design, always do the least surprising thing.
11.

Rule of Silence: When a program has nothing surprising to say, it should say nothing.
12.

Rule of Repair: When you must fail, fail noisily and as soon as possible.
13.

Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
14.

Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
15.

Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
16.

Rule of Diversity: Distrust all claims for “one true way”.
17.

Rule of Extensibility: Design for the future, because it will be here sooner than you think.
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
联系:

#7

帖子 BigSnake.NET » 2008-06-12 10:04

他舍友代码看起来混乱只是因为把stack的实现也放在一起了..
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#8

帖子 flyinflash » 2008-06-12 13:10

tscmga
我是非常欢迎您在我的主题里面引用非中文资料的,:D 但是,请您要么不发,要发就应该附上中文翻译(哪怕是非常蹩足、粗糙的),因为这里不是我和您的交流平台,而是大家的交流平台 :D :D


BigSnake.NET
从功能上来说,我舍友的算术表达式比我的括号匹配要复杂得多。
1、它的算术表达式有括号匹配功能
2、这的算术表达式有算术等级运算功能


我觉得,算法越复杂,代码可读性越差,反之,算法越简单,代码可读性越好。
影响代码可读性因素还有:代码排版风格,变量名命名,语句逻辑实现等等
他舍友代码看起来混乱只是因为把stack的实现也放在一起了..
有经验的人,算法很复杂,也可以通过良好的排版、变量名、语句逻辑实现来改进代码的可读性。

我不喜欢舍友的代码主要因为可读性差,而不是算法复杂。
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
联系:

#9

帖子 BigSnake.NET » 2008-06-12 13:13

flyinflash 写了:tscmga
我是非常欢迎您在我的主题里面引用非中文资料的,:D 但是,请您要么不发,要发就应该附上中文翻译(哪怕是非常蹩足、粗糙的),因为这里不是我和您的交流平台,而是大家的交流平台 :D :D


BigSnake.NET
从功能上来说,我舍友的算术表达式比我的括号匹配要复杂得多。
1、它的算术表达式有括号匹配功能
2、这的算术表达式有算术等级运算功能


我觉得,算法越复杂,代码可读性越差,反之,算法越简单,代码可读性越好。
影响代码可读性因素还有:代码排版风格,变量名命名,语句逻辑实现等等

他舍友代码看起来混乱只是因为把stack的实现也放在一起了..
有经验的人,算法很复杂,也可以通过良好的排版、变量名、语句逻辑实现来改进代码的可读性。

我不喜欢舍友的代码主要因为可读性差,而不是算法复杂。
这个不一定的
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#10

帖子 flyinflash » 2008-06-12 19:39

六楼引用的东西又长又臭。

下面是我写的:

代码: 全选

yuki@yuki-laptop:/home/share/enl$ cat /home/share/project/程序槃涅.txt 
1、程序永远不会达到完整、完善、完美

成品不会变,但是需求总会随着时间的变化而变化。此时,所谓的“成品”程序在广泛的使用中
则会显现出许多设计者意想不到的漏洞和缺憾,变得越来越丑陋和没有价值。要么全部重写一
个新的取代旧的,要么继续完美。

好程序永远都是“测试版”。


2、程序设计核心理念:先让它实现基本功能,不管它效率低、代码冗余

从程序一开始设计就尝试使用复杂的算法,增加了设计者理解、调试代码的难度,使开发期和调
试期变得更长。


3、单元与跟踪调试是主要的除错手段


4、化整为零,支持插件系统

我需要这个,不需要那个,但是这个在甲程序有,那个乙程序有,甲乙是同类软件,我又不想
两个都安装……

Gentoo GNU/Linux 哲学初步实现了近似的功能,但是安装、配置、熟悉 Gentoo 的过程
是很烦,非常非常烦,它还得继续完美。


5、加入新功能前,确保现有的代码已经没有漏洞


6、面向过程设计也要模块化

尽可能使样式、内容和逻辑三者分离;一个文件实现一个功能,删除一个文件不会影响其它文件(功能),
而仅仅是少了删除文件实现的功能而已。
头像
tscmga
帖子: 274
注册时间: 2008-03-16 23:09

#11

帖子 tscmga » 2008-06-13 3:51

哈哈。我觉得翻译成中文就没那个意思了。如果我要搞一原则作为我编程的指导方针,那个16条就是。如果你说又长又臭,反正我是觉得就非常精辟,简洁,易记,高屋建瓴的。里面反映的问题都是非常深刻的。里面考虑到了生产率,人机界面,程序稳健,维护这些。每一天,我都觉得自己领会得太晚了。
您说又长又臭,简直就是开玩笑。
这个是unix系统上的大牛总结出来的方针。就是最初开发unix的人总结出来的。unix的许多地方都体现了这个方针。
头像
tscmga
帖子: 274
注册时间: 2008-03-16 23:09

#12

帖子 tscmga » 2008-06-13 3:52

每一条
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#13

帖子 flyinflash » 2008-06-13 15:14

他们是神,我们应该尊敬他们,但是不是盲从。
适合他们的,不一定适合我们。当然,适合我的,不一定适合你的。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#14

帖子 flyinflash » 2008-06-13 15:14

拿篇文章说明。这篇文章还是我写的,文章状态是:还没有完成 :D :D



yuki@yuki-laptop:~$ cat /home/share/txt/关于\ Linux\ 的几个谎言.txt
关于 Linux 的几个谎言



1、开发人员必学一种命令行编辑器,普通用户也应该学一种

使用过带小红点(TracePoint)的 Lenovo Thinkpad 笔记本计算机,并且使用期在半年以上吗?

推荐学命令行编辑器一般广告词有两句:
1、编辑效率高
2、没有图形界面,节省系统资源

下面以两大流行的命令行编辑器 VIM 和 Emacs 为例。
缺点:
1、学习它们要花费大量时间记忆、练习枯燥的命令;
2、如果使用 VIM 时需按 ESC 来在两种状态中不停切换,而 ESC 键距离 ASDF 键不近;
不管是 VIM 还是 Emacs,删除、替换、复制都需要按两个键以上,有些操作还要“心算”;
3、在修改编辑器设置之前,必须看手册,了解每个选项的命令语法。

优点:编辑效率高主要体现不需要使用鼠标,移动光标快、定位准。


使用 Lenovo Thinkpad 笔记本计算机和图形界面编辑器 Kate 组合。
缺点:
我实在想不到。

优点:
1、移动光标快、定位准,并且只需左右手任意一个食指头,食指头还不需离开 F 和 J 键;
2、删除、替换、复制简单、直接、直观;
3、在修改编辑器设置之前,不須看手册。


Kate 运行时使用内存不超过 20 兆字节,VIM 和 Emacs 的确比 Kate 少得多。


记住 Kate 中几个常用的快捷键:
1、CTRL + K,删除整行
2、CTRL + D,注释整行


综上,绝大部分开发人员和普通用户没有必要学习命令行编辑器。

我推荐您们在购机时,不管是台式机,还是笔记本,都应该首选 Lenovo Thinkpad 笔记本计算机。



2、Linux 计算机操作系统比其它非类 Linux 安全

程序是人写的,人做任何事情都有疏忽的时候。

程序不外乎就是顺序,逻辑判断,循环,假定第个函数或模块在这三个环节里面有漏洞或出错的概率都是 1/1000 ,
那么一个系统大概由 100000 函数组成,某系统有安全漏洞概率估算为:
security_bug = 3 * 1/1000 * 100000 * k = 0.003 * k,
k = users * (golden_section)^(develop_users * open_source_limit),

users 是用户数,golden_section 是黄金分割数,develop_users 是开发人员数,open_source_limit 是
系统源代码对外开放度。

用户数越多,发现安全漏洞越容易,开发人员数越多越广越专业修复安全漏洞越快越容易,系统源代码对外开放度越高
修复安全漏洞越快越容易。

类 Unix 系统比其它系统较安全的原因:
1、全球用户总量比较少;
2、系统内核设计优秀而复杂;
3、安全补丁发布迅速,系统开发更新周期短。

从 2008 年的奇客新闻集中池和每年世界软件级骇客比赛知道,三大主流系统:类 Unix,Mac 和 Windows Vista 都有安全
漏洞。

综上:高度安全意识的人(60%) + 高度安全的 Linux 操作系统(30%) = 高度安全(90%)



3、Linux 计算机操作系统比其它非类 Linux 上手和管理更难

非类 Linux 系统安装一个软件的过程:
打开浏览器寻找-->判断有没有包含恶意代码、插件-->下载-->安装前设置-->安装-->安装后设置。
如果是商业软件或者共享软件:
寻找-->判断有没有包含恶意代码、插件-->下载-->安装前设置-->安装-->寻找软件破解-->判断软件破解器有没有包含恶意代码、插件-->安装后设置。

Linux 系统安装一个软件的过程:
打开软件包管理器寻找并确定安装-->安装后设置。

其中 Linux 系统安装一个软件,从互联网上下载软件,判断有没有包含恶意代码、插件,安装前设置,安装都是由软件包管理器自动完成的,另外,如果
用户喜欢自找麻烦,也可以选择像非类 Linux 系统安装方式一样安装软件。不管是哪一种安装方式,99.9% 的概率都不需要软件破解器,因为类 Linux
系统下面的 99.9% 的软件都是自由、免费、开源、优质的。


我使用 Linux 玩具清单:
Linux Toy List 2008

Disctribution Ubuntu GNU/Linux
Desktop Enviroment GNOME
Terminal GNOME-Terminal, tilda
Dictionary stardict, sdcv
Input SCIM
Download Accelerator Axel

Broswer Firefox, Konqueror
Audio Player Amarok
Video Player Mplayer
Editor Kate
Programming IDE Geany
FTP Slient gFTP
Image Editor GIMP
Image View gThumb
Screen Snapshot KSnapshot
Screen Capture XVidCap
Calculator Gcalctool
PDF Reader Adobe Reader
CHM Reader Kchmviewer
Office OOo, AbiWord

FTP Server vsFTP
Web Server Apache
SQL Server MySQL
SMB Server Samba

它们能满足我学习、工作、娱乐所有要求,值得一提的是 shuge.org (舒阁项目)就是使用这些 GNU 软件完成的,
没有使用到任何一个 Windows 下的程序。



作者李蠡系
中国广州|自由同盟 成员
毓琦图书馆项目主管,毓琦图书馆系统主要设计和实现者

他使用过的操作系统有 Windows 98,Windows ME,Windows 2000,Windows XP,Windows Vista,Ubuntu GNU/Linux,
Gentoo GNU/Linux,Federa GNU/Linux。从 2000 年开始使用 Windows,从 2006 年开始使用 Linux。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28

#15

帖子 flyinflash » 2008-06-13 15:16

很多大牛都认为小牛要学、应学 命令行编辑器,有些小牛因为“崇拜”大牛,觉得他们是对的,什么都是对的,只要是大牛说的,可是,事实真的是对的么? :D
回复