数据结构可以通过组合建立层次结构。原子数据类型,例如int、char、double和枚举类型在层次结构的最底层。为了表示更加复杂的信息,可以通过数组、记录和指针三种基本的构建方法将这些原子类型组合成较大的结构。这些较大的结构可以组合成更大的结构,这是一个无穷的过程。
如果某一个类型的定义更注重它的行为而非表示,按照它的行为而非它的表示方式定义的类型就称为抽象数据类型,缩写为ADT。
栈是这样一种编程结构:它的抽象行为特征为从栈中删除元素的顺序与加入元素的顺序相反(后进先出,last in first out,LIFO)。最后加入的元素最先出来。向栈中加入一个新值称为“入栈”,删除一个最新的值称为“出栈”。
栈中的数据值的类型必须由客户来决定。遗憾的是ANSI C没有为定义多态的接口提供一种理想的机制,以便使得同一个接口可以处理很多不同的类型。尽管限制了客户使用指针的类型,但是通过使用void *类型作为基础类型可以在一定程度上实现多态性。另一种方法是根据一种新的类型如stackElementT定义接口,这样使任何对于基础类型的依赖性都限制在单个的定义上。
定义栈为ADT使得改变他们的底层表示而客户不需要改变他们的代码成为了可能。在本章中,栈使用了静态和动态数组两种实现方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef _stack_h
#define _stack_h
typedef enum {false, true} bool;
typedef char stackElementT;
typedef struct stackCDT * stackADT;
stackADT NewStack(void);
void FreeStack(stackADT stack);
void Push(stackADT stack, stackElementT element);
stackElementT Pop(stackADT stack);
bool StackIsEmpty(stackADT stack);
bool StackIsFull(stackADT stack);
int StackDepth(stackADT stack);
stackElementT GetStackElement(stackADT stack, int index);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdlib.h>
#include "stack.h"
#define MaxStackSize 100
struct stackCDT{
stackElementT elements[MaxStackSize];
int count;
};
stackADT NewStack(void){
stackADT stack;
stack = malloc(sizeof (* stack));
stack->count = 0;
return (stack);
}
void FreeStack(stackADT stack){
free(stack);
}
void Push(stackADT stack, stackElementT element){
if(!StackIsFull(stack)){
stack->elements[stack->count++] = element;
}
}
stackElementT Pop(stackADT stack){
if(!StackIsEmpty(stack)){
return (stack->elements[--stack->count]);
}
}
bool StackIsEmpty(stackADT stack){
return (stack->count == 0);
}
bool StackIsFull(stackADT stack){
return (stack->count == MaxStackSize);
}
int StackDepth(stackADT stack){
return (stack->count);
}
stackElementT GetStackElement(stackADT stack, int index){
if(index>=0 && index<stack->count){
return (stack->elements[stack->count - index - 1]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdlib.h>
#include "stack.h"
#define InitialStackSize 100
struct stackCDT{
stackElementT * elements;
int count;
int size;
};
static void ExpandStack(stackADT stack){
stackElementT *array;
int i, newSize;
newSize = stack->size * 2;
array = malloc(newSize * sizeof(stackElementT));
for(i=0; i<stack->size; i++){
array[i] = stack->elements[i];
}
free(stack->elements);
stack->elements = array;
stack->size = newSize;
}
stackADT NewStack(void){
stackADT stack;
stack = malloc(sizeof (* stack));
stack->elements = malloc(InitialStackSize * sizeof(stackElementT));
stack->count = 0;
stack->size = InitialStackSize;
return (stack);
}
void FreeStack(stackADT stack){
free(stack->elements);
free(stack);
}
void Push(stackADT stack, stackElementT element){
if(stack->count == stack->size){
ExpandStack(stack);
}
stack->elements[stack->count++] = element;
}
stackElementT Pop(stackADT stack){
if(!StackIsEmpty(stack)){
return (stack->elements[--stack->count]);
}
}
bool StackIsEmpty(stackADT stack){
return (stack->count == 0);
}
bool StackIsFull(stackADT stack){
return (false);
}
int StackDepth(stackADT stack){
return (stack->count);
}
stackElementT GetStackElement(stackADT stack, int index){
if(index>=0 && index<stack->count){
return (stack->elements[stack->count - index - 1]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdlib.h>
#include "stack.h"
typedef struct cellT{
stackElementT element;
struct cellT * link;
} cellT;
struct stackCDT{
cellT * start;
};
stackADT NewStack(void){
stackADT stack;
stack = malloc(sizeof (* stack));
stack->start = NULL;
return (stack);
}
void FreeStack(stackADT stack){
cellT *cp, *next;
cp = stack->start;
while(cp != NULL){
next = cp->link;
free(cp);
cp = next;
}
free(stack);
}
void Push(stackADT stack, stackElementT element){
cellT *cp;
cp = malloc(sizeof (*cp));
cp->element = element;
cp->link = stack->start;
stack->start = cp;
}
stackElementT Pop(stackADT stack){
cellT *cp;
stackElementT element;
if(!StackIsEmpty(stack)){
element = stack->start->element;
cp = stack->start;
stack->start = cp->link;
free(cp);
}
// 此处存在错误,当是空栈时应该抛出异常
return element;
}
bool StackIsEmpty(stackADT stack){
return (stack->start == NULL);
}
bool StackIsFull(stackADT stack){
return (false);
}
int StackDepth(stackADT stack){
int count;
cellT *cp;
count = 0;
cp = stack->start;
while(cp != NULL){
cp = cp->link;
count++;
}
return count;
}
stackElementT GetStackElement(stackADT stack, int index){
int i;
cellT *cp;
if(index>=0 && index<(StackDepth(stack))){
cp = stack->start;
for(i=0; i<index; i++){
cp = cp->link;
}
}
// 此处存在错误,当是空栈时应该抛出异常
return cp->element;
}
编辑器在内部维护的是字符的序列,通常称为缓冲区。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef _buffer_h
#define _buffer_h
typedef struct bufferCDT * bufferADT;
bufferADT NewBuffer(void);
void FreeBuffer(bufferADT buffer);
void MoveCursorForward(bufferADT buffer);
void MoveCursorBackward(bufferADT buffer);
void MoveCursorToStart(bufferADT buffer);
void MoveCursorToEnd(bufferADT buffer);
void InsertCharacter(bufferADT buffer, char ch);
void DeleteCharacter(bufferADT buffer);
void DisplayBuffer(bufferADT buffer);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "buffer.h"
typedef char *string;
typedef enum {false, true} bool;
static void ExecuteCommand(bufferADT buffer, string line);
static void HelpCommand(void);
main(){
char str[80];
bufferADT buffer;
buffer = NewBuffer();
while(true){
printf("* ");
scanf("%s", str);
ExecuteCommand(buffer, str);
DisplayBuffer(buffer);
}
FreeBuffer(buffer);
}
static void ExecuteCommand(bufferADT buffer, string line){
int i;
switch(toupper(line[0])){
case 'I':
for(i=1; line[i]!= '\0'; i++){
InsertCharacter(buffer, line[i]);
}
break;
case 'D':
DeleteCharacter(buffer);
break;
case 'F':
MoveCursorForward(buffer);
break;
case 'B':
MoveCursorBackward(buffer);
break;
case 'J':
MoveCursorToStart(buffer);
break;
case 'E':
MoveCursorToEnd(buffer);
break;
case 'H':
HelpCommand();
break;
case 'Q':
exit(0);
default:
printf("Illegal command\n");
break;
}
}
static void HelpCommand(void){
printf("Use the following commands to edit the buffer: \n");
printf(" I Inserts text up to the end of the line\n");
printf(" F Moves forward a character\n");
printf(" B Moves backword a character\n");
printf(" J Jumps to the beginning of the buffer\n");
printf(" E Jumps to the end of the buffer\n");
printf(" D Deletes the next character\n");
printf(" H Cenerates a help message\n");
printf(" Q Quits the program\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include "buffer.h"
#define MaxBuffer 100
struct bufferCDT{
char text[MaxBuffer];
int length;
int cursor;
};
bufferADT NewBuffer(void){
bufferADT buffer;
buffer = malloc(sizeof *buffer);
buffer->length = buffer->cursor = 0;
return (buffer);
}
void FreeBuffer(bufferADT buffer){
free(buffer);
}
void MoveCursorForward(bufferADT buffer){
if(buffer->cursor < buffer->length){
buffer->cursor++;
}
}
void MoveCursorBackward(bufferADT buffer){
if(buffer->cursor > 0){
buffer->cursor--;
}
}
void MoveCursorToStart(bufferADT buffer){
buffer->cursor = 0;
}
void MoveCursorToEnd(bufferADT buffer){
buffer->cursor = buffer->length;
}
void InsertCharacter(bufferADT buffer, char ch){
int i;
if(buffer->length == MaxBuffer){
return;
}
for(i=buffer->length; i>buffer->cursor; i--){
buffer->text[i] = buffer->text[i-1];
}
buffer->text[buffer->cursor] = ch;
buffer->length++;
buffer->cursor++;
}
void DeleteCharacter(bufferADT buffer){
int i;
if(buffer->cursor < buffer->length){
for(i=buffer->cursor+1; i<buffer->length; i++){
buffer->text[i-1] = buffer->text[i];
}
buffer->length--;
}
}
void DisplayBuffer(bufferADT buffer){
int i;
for(i=0; i<buffer->length; i++){
printf("%c", buffer->text[i]);
}
printf("\n");
for(i=0; i<buffer->cursor; i++){
printf(" ");
}
printf("^\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#include "buffer.h"
struct bufferCDT{
stackADT before;
stackADT after;
};
bufferADT NewBuffer(void){
bufferADT buffer;
buffer = malloc(sizeof *buffer);
buffer->before = NewStack();
buffer->after = NewStack();
return (buffer);
}
void FreeBuffer(bufferADT buffer){
FreeStack(buffer->before);
FreeStack(buffer->after);
free(buffer);
}
void MoveCursorForward(bufferADT buffer){
if(!StackIsEmpty(buffer->after)){
Push(buffer->before, Pop(buffer->after));
}
}
void MoveCursorBackward(bufferADT buffer){
if(!StackIsEmpty(buffer->before)){
Push(buffer->after, Pop(buffer->before));
}
}
void MoveCursorToStart(bufferADT buffer){
while(!StackIsEmpty(buffer->before)){
Push(buffer->after, Pop(buffer->before));
}
}
void MoveCursorToEnd(bufferADT buffer){
while(!StackIsEmpty(buffer->after)){
Push(buffer->before, Pop(buffer->after));
}
}
void InsertCharacter(bufferADT buffer, char ch){
Push(buffer->before, ch);
}
void DeleteCharacter(bufferADT buffer){
if(StackIsEmpty(buffer->after)){
Pop(buffer->after);
}
}
void DisplayBuffer(bufferADT buffer){
int i;
int blen = StackDepth(buffer->before);
int alen = StackDepth(buffer->after);
for(i=blen-1; i>=0; i--){
printf("%c", GetStackElement(buffer->before, i));
}
for(i=0; i<alen; i++){
printf("%c", GetStackElement(buffer->after, i));
}
printf("\n");
for(i=0; i<blen; i++){
printf(" ");
}
printf("^\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <stdio.h>
#include <stdlib.h>
#include "buffer.h"
typedef struct cellT{
char value;
struct cellT * link;
} cellT;
struct bufferCDT{
cellT * start;
cellT * cursor;
};
bufferADT NewBuffer(void){
bufferADT buffer;
buffer = malloc(sizeof *buffer);
buffer->start = buffer->cursor = malloc(sizeof(cellT));
buffer->start->link = NULL;
return (buffer);
}
void FreeBuffer(bufferADT buffer){
cellT *cp, *next;
cp = buffer->start;
while(cp != NULL){
next = cp->link;
free(cp);
cp = next;
}
free(buffer);
}
void MoveCursorForward(bufferADT buffer){
if(buffer->cursor->link != NULL){
buffer->cursor = buffer->cursor->link;
}
}
void MoveCursorBackward(bufferADT buffer){
cellT *cp;
if(buffer->start != buffer->cursor){ // 此处判断可以省略,逻辑不会出现错误
cp = buffer->start;
while(cp->link != buffer->cursor){
cp = cp->link;
}
buffer->cursor = cp;
}
}
void MoveCursorToStart(bufferADT buffer){
buffer->cursor = buffer->start;
}
void MoveCursorToEnd(bufferADT buffer){
while(buffer->cursor->link != NULL){
// MoveCursorForward(buffer);
buffer->cursor = buffer->cursor->link;
}
}
void InsertCharacter(bufferADT buffer, char ch){
cellT *cp = malloc(sizeof(cellT));
cp->value = ch;
cp->link = buffer->cursor->link;
buffer->cursor->link = cp;
buffer->cursor = cp;
}
void DeleteCharacter(bufferADT buffer){
cellT *cp;
if(buffer->cursor->link != NULL){
cp = buffer->cursor->link;
buffer->cursor->link = cp->link;
free(cp);
}
}
void DisplayBuffer(bufferADT buffer){
cellT *cp;
for(cp=buffer->start->link; cp!=NULL; cp=cp->link){
printf("%c", cp->value);
}
printf("\n");
for(cp=buffer->start; cp!=buffer->cursor; cp=cp->link){
printf(" ");
}
printf("^\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <stdlib.h>
#include "buffer.h"
typedef struct cellT{
char value;
struct cellT * prev;
struct cellT * next;
} cellT;
struct bufferCDT{
cellT * start;
cellT * cursor;
};
bufferADT NewBuffer(void){
bufferADT buffer;
buffer = malloc(sizeof *buffer);
buffer->start = buffer->cursor = malloc(sizeof(cellT));
buffer->start->next = buffer->start;
buffer->start->prev = buffer->start;
return (buffer);
}
void InsertCharacter(bufferADT buffer, char ch){
cellT *cp = malloc(sizeof(cellT));
cp->value = ch;
cp->next = buffer->cursor->next;
cp->prev = buffer->cursor;
cp->next->prev = cp;
buffer->cursor->next = cp;
buffer->cursor = cp;
}
void DeleteCharacter(bufferADT buffer){
cellT *cp;
if(buffer->cursor->next != buffer->start){
cp = buffer->cursor->next;
buffer->cursor->next = cp->next;
cp->next->prev = buffer->cursor;
free(cp);
}
}
void FreeBuffer(bufferADT buffer){
cellT *cp, *next;
cp = buffer->start;
do{
next = cp->next;
free(cp);
cp = next;
}while(cp != buffer->start);
free(buffer);
}
void MoveCursorForward(bufferADT buffer){
if(buffer->cursor->next != buffer->start){
buffer->cursor = buffer->cursor->next;
}
}
void MoveCursorBackward(bufferADT buffer){
if(buffer->cursor->prev != buffer->start->prev){
buffer->cursor = buffer->cursor->prev;
}
}
void MoveCursorToStart(bufferADT buffer){
buffer->cursor = buffer->start;
}
void MoveCursorToEnd(bufferADT buffer){
buffer->cursor = buffer->start->prev;
}
void DisplayBuffer(bufferADT buffer){
cellT *cp;
for(cp=buffer->start->next; cp!=buffer->start; cp=cp->next){
printf("%c", cp->value);
}
printf("\n");
for(cp=buffer->start; cp!=buffer->cursor; cp=cp->next){
printf(" ");
}
printf("^\n");
}
以FIFO(first in, first out)规则存储其数据项的数据结构称为队列。队列的基本操作与栈的压入和弹出操作类似,即Enqueue和Dequeue。入队操作在队列的最后(队尾)增加一个新元素。出队操作删除在队列最前面(队首)的一个元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef _queue_h
#define _queue_h
#include <stdlib.h>
typedef enum {false, true} bool;
typedef void *queueElementT;
typedef struct queueCDT *queueADT;
queueADT NewQueue(void);
void FreeQueue(queueADT queue);
void Enqueue(queueADT queue, queueElementT element);
queueElementT Dequeue(queueADT queue);
bool QueueIsEmpty(queueADT queue);
bool QueueIsFull(queueADT queue);
int QueueLength(queueADT queue);
queueElementT GetQueueElement(queueADT queue, int index);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "queue.h"
#define MaxQueueSize 100
#define QueueArraySize (MaxQueueSize+1)
struct queueCDT{
queueElementT elements[QueueArraySize];
int head;
int tail;
};
queueADT NewQueue(void){
queueADT queue;
queue = malloc(sizeof (*queue));
queue->head = queue->tail = 0;
return (queue);
}
void FreeQueue(queueADT queue){
free(queue);
}
void Enqueue(queueADT queue, queueElementT element){
int tail;
if(!QueueIsFull(queue)){
queue->elements[tail] = element;
queue->tail = (queue->tail + 1) % QueueArraySize;
}
}
queueElementT Dequeue(queueADT queue){
queueElementT element;
if(!QueueIsEmpty(queue)){
element = queue->elements[queue->head];
queue->head = (queue->head + 1) % QueueArraySize;
return (element);
}
}
bool QueueIsEmpty(queueADT queue){
return (queue->head == queue->tail);
}
bool QueueIsFull(queueADT queue){
return ((queue->tail+1)%QueueArraySize == queue->head);
}
int QueueLength(queueADT queue){
return ((queue->tail - queue->head + QueueArraySize) % QueueArraySize);
}
queueElementT GetQueueElement(queueADT queue, int index){
if(index>=0 && index<QueueLength(queue)){
return (queue->elements[(queue->head + index) % QueueArraySize]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "queue.h"
typedef struct cellT{
queueElementT element;
struct cellT *link;
} cellT;
struct queueCDT{
cellT *head;
cellT *tail;
};
queueADT NewQueue(void){
queueADT queue;
queue = malloc(sizeof (*queue));
queue->head = NULL;
return queue;
}
void FreeQueue(queueADT queue){
cellT *cp, *next;
cp = queue->head;
while(cp != NULL){
next = cp->link;
free(cp);
cp = next;
}
free(queue);
}
void Enqueue(queueADT queue, queueElementT element){
cellT *cp;
cp = malloc(sizeof (*cp));
cp->element = element;
cp->link = NULL;
if(queue->head == NULL){
queue->head = cp;
}
else{
queue->tail->link = cp;
}
queue->tail = cp;
}
queueElementT Dequeue(queueADT queue){
cellT *cp;
queueElementT element;
if(!QueueIsEmpty(queue)){
cp = queue->head;
element = cp->element;
queue->head = cp->link;
free(cp);
return (element);
}
}
bool QueueIsEmpty(queueADT queue){
return (queue->head == NULL);
}
bool QueueIsFull(queueADT queue){
return (false);
}
int QueueLength(queueADT queue){
int n;
cellT *cp;
for(n=0,cp=queue->head; cp!=NULL; cp=cp->link){
n++;
}
return (n);
}
queueElementT GetQueueElement(queueADT queue, int index){
int i;
cellT *cp;
if(index>=0 && index<QueueLength(queue)){
cp = queue->head;
for(i=1; i<index; i++){
cp = cp->link;
}
return (cp->element);
}
}