读《程序是怎样跑起来的》第4章

   指针指的是用于存储内存地址的变量;物理内存以字节为单位进行数据存储的;栈是一种后入先出(LIFO=Last In First Out)式的数据结构;二叉查找树指的是从节点分成两个叉的树状数据结构。内存IC中有电源、地址信号、数据信号、控制信号等用于输入输出的大量引脚(IC的引脚),通过为其指定地址(address),来进行数据的读写。

  1 #include "stdio.h"    
  2 #include "stdlib.h"   
  3 #include "io.h"  
  4 #include "math.h"  
  5 #include "time.h"
  6 
  7 #define OK 1
  8 #define ERROR 0
  9 #define TRUE 1
 10 #define FALSE 0
 11 #define MAXSIZE 20 /* 存储空间初始分配量 */
 12 
 13 typedef int Status; 
 14 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
 15 
 16 /* 顺序栈结构 */
 17 typedef struct
 18 {
 19         SElemType data[MAXSIZE];
 20         int top; /* 用于栈顶指针 */
 21 }SqStack;
 22 
 23 Status visit(SElemType c)
 24 {
 25         printf("%d ",c);
 26         return OK;
 27 }
 28 
 29 /*  构造一个空栈S */
 30 Status InitStack(SqStack *S)
 31 { 
 32         /* S.data=(SElemType *)malloc(MAXSIZE*sizeof(SElemType)); */
 33         S->top=-1;
 34         return OK;
 35 }
 36 
 37 /* 把S置为空栈 */
 38 Status ClearStack(SqStack *S)
 39 { 
 40         S->top=-1;
 41         return OK;
 42 }
 43 
 44 /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
 45 Status StackEmpty(SqStack S)
 46 { 
 47         if (S.top==-1)
 48                 return TRUE;
 49         else
 50                 return FALSE;
 51 }
 52 
 53 /* 返回S的元素个数,即栈的长度 */
 54 int StackLength(SqStack S)
 55 { 
 56         return S.top+1;
 57 }
 58 
 59 /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
 60 Status GetTop(SqStack S,SElemType *e)
 61 {
 62         if (S.top==-1)
 63                 return ERROR;
 64         else
 65                 *e=S.data[S.top];
 66         return OK;
 67 }
 68 
 69 /* 插入元素e为新的栈顶元素 */
 70 Status Push(SqStack *S,SElemType e)
 71 {
 72         if(S->top == MAXSIZE -1) /* 栈满 */
 73         {
 74                 return ERROR;
 75         }
 76         S->top++;                /* 栈顶指针增加一 */
 77         S->data[S->top]=e;  /* 将新插入元素赋值给栈顶空间 */
 78         return OK;
 79 }
 80 
 81 /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
 82 Status Pop(SqStack *S,SElemType *e)
 83 { 
 84         if(S->top==-1)
 85                 return ERROR;
 86         *e=S->data[S->top];    /* 将要删除的栈顶元素赋值给e */
 87         S->top--;                /* 栈顶指针减一 */
 88         return OK;
 89 }
 90 
 91 /* 从栈底到栈顶依次对栈中每个元素显示 */
 92 Status StackTraverse(SqStack S)
 93 {
 94         int i;
 95         i=0;
 96         while(i<=S.top)
 97         {
 98                 visit(S.data[i++]);
 99         }
100         printf("\n");
101         return OK;
102 }
103 
104 int main()
105 {
106         int j;
107         SqStack s;
108         int e;
109         if(InitStack(&s)==OK)
110                 for(j=1;j<=10;j++)
111                         Push(&s,j);
112         printf("栈中元素依次为:");
113         StackTraverse(s);
114         Pop(&s,&e);
115         printf("弹出的栈顶元素 e=%d\n",e);
116         printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
117         GetTop(s,&e);
118         printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
119         ClearStack(&s);
120         printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
121         
122         return 0;
123 }

 

  随机存取存储器,又称做随机存储器是与CPU直接交换数据的内部存储器,主存主要是指RAM。RAM随时时读写,而且速度很快,但当电源关闭时不能保留数据,通常作为操作系统或其它正在运行中的程序的临时数据存储媒介。主存是计算机内部最主要的内存用来加载各式各样的程序与数据,一共cpu直接使用RAM可以分为动态随机存储器DRAM和静态随机存储器SRAM两大类。DRAM需要定时刷新单,由于具有较低的单位价格,扩展性也不错,所以也被大量的采用作为系统的主存。而SRAM不需要刷新,因此具有快速访问的优点,生产成本较昂贵,一个典型的应用就是高速缓存。

  使用高速缓存的原因:由于CPU的运行速度一般比内存的读取速度快,而且内存周期(访问内存所需要的时间)为数个时钟周期,因此若要访问内存就必须等待数个CPU时钟周期,从而造成浪费。

高速缓存的基本原理:是内存中”程序执行与数据访问的局域性行为”,即一定程序执行时间和空间内被访问的代码集中于一部分。为了充分发挥高速缓存的作用,不仅依靠“暂存刚刚访问过的数据”还要使用硬件实现指令的预测和数据预取技术,尽可能把将要使用的数据预先从内存中取到高速缓存中。

  只读存储器ROM,是一种半导体存储器,其特性是一旦存储数据就无法再将之改变,或删除其数据,只能读不能写入和修改。其内容不会因为电源关闭而消失,通常用于存储,不需要经常变更的程序和数据,如BIOS和启动程序。

  固件是一种嵌入在硬件设备的软件(程序和数据),固件位于软件和硬件之间,是软件和硬件的合成品,通常它位于特殊的应用集成电路(ASIC)或可编程逻辑器件PLD之中的闪存或EEPROM或PROM里,有的可以让用户更新。固件广泛应用于在各种电子产品中,从计算器到计算机的键盘、硬盘、内存卡、甚至科学计算和工业机器人。日常生活中的移动电话,数码相机,电视遥控器等均包含固件,以执行设备的基本操作和高级功能。

  互补式金属氧化物半导体(CMOS)是一种集成电路,半导体可在硅晶圆上制作出PMOS(正极)和NMOS(负极)元件,由于PMOS与NMOS在特性上为互补性,因此称为CMOS。此半导体可用来制作微处理器(Microprocessor)、微控制器(Microcontroller)、静态随机存取内存(SRAM)以及其他数位逻辑电路。CMOS具有只有在晶体管需要切换启闭时才需耗能的优点,非常省电且发热少,因此特别适合电池供电的设备。个人计算机中有一个电池供电的CMOS,存储系统日期、时间、启动参数等。即CMOS:存储计算机的启动信息;存储计算机的配置信息(如磁盘驱动器类型、键盘、显示器等)。

  1 #include "stdio.h"    
  2 #include "stdlib.h"   
  3 #include "io.h"  
  4 #include "math.h"  
  5 #include "time.h"
  6 
  7 #define OK 1
  8 #define ERROR 0
  9 #define TRUE 1
 10 #define FALSE 0
 11 #define MAXSIZE 20 /* 存储空间初始分配量 */
 12 
 13 typedef int Status; 
 14 typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
 15 
 16 /* 循环队列的顺序存储结构 */
 17 typedef struct
 18 {
 19     QElemType data[MAXSIZE];
 20     int front;        /* 头指针 */
 21     int rear;        /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
 22 }SqQueue;
 23 
 24 Status visit(QElemType c)
 25 {
 26     printf("%d ",c);
 27     return OK;
 28 }
 29 
 30 /* 初始化一个空队列Q */
 31 Status InitQueue(SqQueue *Q)
 32 {
 33     Q->front=0;
 34     Q->rear=0;
 35     return  OK;
 36 }
 37 
 38 /* 将Q清为空队列 */
 39 Status ClearQueue(SqQueue *Q)
 40 {
 41     Q->front=Q->rear=0;
 42     return OK;
 43 }
 44 
 45 /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
 46 Status QueueEmpty(SqQueue Q)
 47 { 
 48     if(Q.front==Q.rear) /* 队列空的标志 */
 49         return TRUE;
 50     else
 51         return FALSE;
 52 }
 53 
 54 /* 返回Q的元素个数,也就是队列的当前长度 */
 55 int QueueLength(SqQueue Q)
 56 {
 57     return  (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
 58 }
 59 
 60 /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
 61 Status GetHead(SqQueue Q,QElemType *e)
 62 {
 63     if(Q.front==Q.rear) /* 队列空 */
 64         return ERROR;
 65     *e=Q.data[Q.front];
 66     return OK;
 67 }
 68 
 69 /* 若队列未满,则插入元素e为Q新的队尾元素 */
 70 Status EnQueue(SqQueue *Q,QElemType e)
 71 {
 72     if ((Q->rear+1)%MAXSIZE == Q->front)    /* 队列满的判断 */
 73         return ERROR;
 74     Q->data[Q->rear]=e;            /* 将元素e赋值给队尾 */
 75     Q->rear=(Q->rear+1)%MAXSIZE;/* rear指针向后移一位置, */
 76                                 /* 若到最后则转到数组头部 */
 77     return  OK;
 78 }
 79 
 80 /* 若队列不空,则删除Q中队头元素,用e返回其值 */
 81 Status DeQueue(SqQueue *Q,QElemType *e)
 82 {
 83     if (Q->front == Q->rear)            /* 队列空的判断 */
 84         return ERROR;
 85     *e=Q->data[Q->front];                /* 将队头元素赋值给e */
 86     Q->front=(Q->front+1)%MAXSIZE;    /* front指针向后移一位置, */
 87                                     /* 若到最后则转到数组头部 */
 88     return  OK;
 89 }
 90 
 91 /* 从队头到队尾依次对队列Q中每个元素输出 */
 92 Status QueueTraverse(SqQueue Q)
 93 { 
 94     int i;
 95     i=Q.front;
 96     while((i+Q.front)!=Q.rear)
 97     {
 98         visit(Q.data[i]);
 99         i=(i+1)%MAXSIZE;
100     }
101     printf("\n");
102     return OK;
103 }
104 
105 int main()
106 {
107     Status j;
108     int i=0,l;
109     QElemType d;
110     SqQueue Q;
111     InitQueue(&Q);
112     printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
113 
114     printf("请输入整型队列元素(不超过%d个),-1为提前结束符: ",MAXSIZE-1);
115     do
116     {
117         /* scanf("%d",&d); */
118         d=i+100;
119         if(d==-1)
120             break;
121         i++;
122         EnQueue(&Q,d);
123     }while(i1);
124 
125     printf("队列长度为: %d\n",QueueLength(Q));
126     printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
127     printf("连续%d次由队头删除元素,队尾插入元素:\n",MAXSIZE);
128     for(l=1;l<=MAXSIZE;l++)
129     {
130         DeQueue(&Q,&d);
131         printf("删除的元素是%d,插入的元素:%d \n",d,l+1000);
132         /* scanf("%d",&d); */
133         d=l+1000;
134         EnQueue(&Q,d);
135     }
136     l=QueueLength(Q);
137 
138     printf("现在队列中的元素为: \n");
139     QueueTraverse(Q);
140     printf("共向队尾插入了%d个元素\n",i+MAXSIZE);
141     if(l-2>0)
142         printf("现在由队头删除%d个元素:\n",l-2);
143     while(QueueLength(Q)>2)
144     {
145         DeQueue(&Q,&d);
146         printf("删除的元素值为%d\n",d);
147     }
148 
149     j=GetHead(Q,&d);
150     if(j)
151         printf("现在队头元素为: %d\n",d);
152     ClearQueue(&Q);
153     printf("清空队列后, 队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
154     return 0;
155 }

  数组是内存使用方法的基础,因为数组和内存的物理构造是一样的。特别是以字节类型的数组,它和内存的物理构造完全一致。不过如果只能逐个字节来读写,程序变得比较麻烦,因而可以指定任意数据类型来定义数组。数组还有一些变形方法,栈、队列、链表和二叉查找树。栈和队列都可以不通过指定地址和索引来对数组的元素进行读写。栈和队列的区别在于数据出入的顺序是不同的。在对内存数据进行读写时,栈用的是LIFO(Last Input Fisrt Out)后入先出方式,而队列用的则是FIFO(First Input First Out)先入先出方式。如果我们在内存中预留出栈和队列所需要的空间,并确定好写入和读出的顺序,就不用再指定地址和索引了。在数组的各个元素中,除了数据值之外,通过为其附带上下一个元素的索引,即可实现链表,从而可使得元素的追加和删除更容易。二叉查找树是在链表的基础上往数组中追加元素时,考虑到数据的大小关系,将其分成左右两个方向的表现形式,从而使数据搜索更有效。

  1 #include "string.h"
  2 #include "stdio.h"    
  3 #include "stdlib.h"   
  4 #include "io.h"  
  5 #include "math.h"  
  6 #include "time.h"
  7 
  8 #define OK 1
  9 #define ERROR 0
 10 #define TRUE 1
 11 #define FALSE 0
 12 
 13 #define MAXSIZE 100 /* 存储空间初始分配量 */
 14 
 15 typedef int Status;        /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 16 
 17 /* 用于构造二叉树********************************** */
 18 int index=1;
 19 typedef char String[24]; /*  0号单元存放串的长度 */
 20 String str;
 21 
 22 Status StrAssign(String T,char *chars)
 23 { 
 24     int i;
 25     if(strlen(chars)>MAXSIZE)
 26         return ERROR;
 27     else
 28     {
 29         T[0]=strlen(chars);
 30         for(i=1;i<=T[0];i++)
 31             T[i]=*(chars+i-1);
 32         return OK;
 33     }
 34 }
 35 /* ************************************************ */
 36 
 37 typedef char TElemType;
 38 TElemType Nil=' '; /* 字符型以空格符为空 */
 39 
 40 Status visit(TElemType e)
 41 {
 42     printf("%c ",e);
 43     return OK;
 44 }
 45 
 46 typedef struct BiTNode  /* 结点结构 */
 47 {
 48    TElemType data;        /* 结点数据 */
 49    struct BiTNode *lchild,*rchild; /* 左右孩子指针 */
 50 }BiTNode,*BiTree;
 51 
 52 
 53 /* 构造空二叉树T */
 54 Status InitBiTree(BiTree *T)
 55 { 
 56     *T=NULL;
 57     return OK;
 58 }
 59 
 60 /* 初始条件: 二叉树T存在。操作结果: 销毁二叉树T */
 61 void DestroyBiTree(BiTree *T)
 62 { 
 63     if(*T) 
 64     {
 65         if((*T)->lchild) /* 有左孩子 */
 66             DestroyBiTree(&(*T)->lchild); /* 销毁左孩子子树 */
 67         if((*T)->rchild) /* 有右孩子 */
 68             DestroyBiTree(&(*T)->rchild); /* 销毁右孩子子树 */
 69         free(*T); /* 释放根结点 */
 70         *T=NULL; /* 空指针赋0 */
 71     }
 72 }
 73 
 74 /* 按前序输入二叉树中结点的值(一个字符) */
 75 /* #表示空树,构造二叉链表表示二叉树T。 */
 76 void CreateBiTree(BiTree *T)
 77 { 
 78     TElemType ch;
 79     
 80     /* scanf("%c",&ch); */
 81     ch=str[index++];
 82 
 83     if(ch=='#') 
 84         *T=NULL;
 85     else
 86     {
 87         *T=(BiTree)malloc(sizeof(BiTNode));
 88         if(!*T)
 89             exit(OVERFLOW);
 90         (*T)->data=ch; /* 生成根结点 */
 91         CreateBiTree(&(*T)->lchild); /* 构造左子树 */
 92         CreateBiTree(&(*T)->rchild); /* 构造右子树 */
 93     }
 94  }
 95 
 96 /* 初始条件: 二叉树T存在 */
 97 /* 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE */
 98 Status BiTreeEmpty(BiTree T)
 99 { 
100     if(T)
101         return FALSE;
102     else
103         return TRUE;
104 }
105 
106 #define ClearBiTree DestroyBiTree
107 
108 /* 初始条件: 二叉树T存在。操作结果: 返回T的深度 */
109 int BiTreeDepth(BiTree T)
110 {
111     int i,j;
112     if(!T)
113         return 0;
114     if(T->lchild)
115         i=BiTreeDepth(T->lchild);
116     else
117         i=0;
118     if(T->rchild)
119         j=BiTreeDepth(T->rchild);
120     else
121         j=0;
122     return i>j?i+1:j+1;
123 }
124 
125 /* 初始条件: 二叉树T存在。操作结果: 返回T的根 */
126 TElemType Root(BiTree T)
127 { 
128     if(BiTreeEmpty(T))
129         return Nil;
130     else
131         return T->data;
132 }
133 
134 /* 初始条件: 二叉树T存在,p指向T中某个结点 */
135 /* 操作结果: 返回p所指结点的值 */
136 TElemType Value(BiTree p)
137 {
138     return p->data;
139 }
140 
141 /* 给p所指结点赋值为value */
142 void Assign(BiTree p,TElemType value)
143 {
144     p->data=value;
145 }
146 
147 /* 初始条件: 二叉树T存在 */
148 /* 操作结果: 前序递归遍历T */
149 void PreOrderTraverse(BiTree T)
150 { 
151     if(T==NULL)
152         return;
153     printf("%c",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
154     PreOrderTraverse(T->lchild); /* 再先序遍历左子树 */
155     PreOrderTraverse(T->rchild); /* 最后先序遍历右子树 */
156 }
157 
158 /* 初始条件: 二叉树T存在 */
159 /* 操作结果: 中序递归遍历T */
160 void InOrderTraverse(BiTree T)
161 { 
162     if(T==NULL)
163         return;
164     InOrderTraverse(T->lchild); /* 中序遍历左子树 */
165     printf("%c",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
166     InOrderTraverse(T->rchild); /* 最后中序遍历右子树 */
167 }
168 
169 /* 初始条件: 二叉树T存在 */
170 /* 操作结果: 后序递归遍历T */
171 void PostOrderTraverse(BiTree T)
172 {
173     if(T==NULL)
174         return;
175     PostOrderTraverse(T->lchild); /* 先后序遍历左子树  */
176     PostOrderTraverse(T->rchild); /* 再后序遍历右子树  */
177     printf("%c",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
178 }
179 
180 
181 int main()
182 {
183     int i;
184     BiTree T;
185     TElemType e1;
186     InitBiTree(&T);
187 
188     
189     StrAssign(str,"ABDH#K###E##CFI###G#J##");
190 
191     CreateBiTree(&T);
192 
193     printf("构造空二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
194     e1=Root(T);
195     printf("二叉树的根为: %c\n",e1);
196 
197     printf("\n前序遍历二叉树:");
198     PreOrderTraverse(T);
199     printf("\n中序遍历二叉树:");
200     InOrderTraverse(T);
201     printf("\n后序遍历二叉树:");
202     PostOrderTraverse(T);
203     ClearBiTree(&T);
204     printf("\n清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
205     i=Root(T);
206     if(!i)
207         printf("树空,无根\n");
208     
209     return 0;
210 }

 

你可能感兴趣的:(读《程序是怎样跑起来的》第4章)