在开始本章节之前,我要说明两个问题:
1 线性表的一个误解
很多人认为,并且严老师的书上也是这么划分,就是将线性表和栈,队列划分开来。其实并不是这么回事,我们可以参考《计算机程序设计艺术》第一卷,第二章。其实线性表包括链表,栈,队列。
2 就是我这里想说一些前些天一个女同学问我的一个问题
她大概是这么说的:NULL是什么啊?p = NULL;是什么意思啊?为什么要等于NULL啊?
我开始一听就有些懵,我不知道怎么样去回答他,后思考了一下,我这样回答了她(也许没这么具体):
NULL就是0.我们在系统中有这么一个定义:
#define NULL 0
p = NULL;就是我们令p指向0,即不指向任何内存空间.至于我们为什么这么做呢?其实就是为我们以后的判断做基础的。
如;若我们不定义p = NULL;也就是说我们不引入NULL.你该如何去遍历一个链表呢?该如和判断一个链表已经结束呢。当然我们可以用length做个计数。但我们无法从指针层面做一个判断了。为什么呢?因为我们定义一个指针,如:int *p;
此时p指向何处我们并不清楚,当然很大程度上编译器会为我们初始化为0,但我们不敢保证。所以我们最好引入一个NULL。作为判断标志。
好的,下面我们正式开始本章节;
这里我们对于线性表也就是用本书的说法了.
线性表的顺序表示和实现
线性表的顺序表示,即元素是存储在一段连续的内存空间之中的,至于这段空间到底需要多大,我们并不知道,我们只能先给他分配一定的内存空间,而后需要的时候再增加分配即可。
对于定义分配空间的初始分配量和增量,我们可以使用宏来完成此任务,为什么要使用宏来完成呢?
1 考虑的程序的清晰性与可读性
2 考虑到以后修改时的方便性
现在我们对顺序链表做一个定义:
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int ElemType;
typedef int Status;
enum {OVERFLOW,OK};
typedef struct
{
ElemType *elem; //链表存储空间的基地址
int length; //链表当前长度
int listsize; //链表的分配空间大小
}SqList;
然后我们按照说上给定的操作一一为它定义:
#include "stdio.h"
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int ElemType;
typedef int Status;
enum {ERROR,OVERFLOW = 0,OK};
typedef struct
{
ElemType *elem; //链表存储空间的基地址
int length; //链表当前长度
int listsize; //链表的分配空间大小
}SqList;
Status InitList(SqList *L)
{
L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L->elem)
{
exit(OVERFLOW);
}
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return OK;
}
Status DestroyList(SqList *L)
{
if (L->elem)
{
free(L->elem);
}
L->elem = NULL;
L->length = 0;
L->listsize = 0;
return OK;
}
Status ClearList(SqList *L)
{
L->length = 0;
return OK;
}
Status ListEmpty(SqList L)
{
if (0 == L.length)
{
return ERROR;
}
return OK;
}
int ListLength(SqList L)
{
return L.length;
}
Status GetElem(SqList L,int i,ElemType *e)
{
if (i <= 0 || i >= L.length)
{
printf("ilegle position : %d(i)",i);
return ERROR;
}
*e = L.elem[i-1];
return OK;
}
int LocateElem(SqList L,ElemType e,Status (*compare)(ElemType lhs,ElemType rhs))
{
int i;
for (i = 0; i < L.length; ++i)
{
if (compare(e,L.elem[i]))
{
return i+1;
}
}
return 0;
}
void PriorElem(SqList L,ElemType cur_e,ElemType *pre_e)
{
int i;
for (i = 0; i < L.length; ++i)
{
if (cur_e == L.elem[i])
{
if (i == 0)
{
printf("%d位于第一个位置,它没有前驱/n",cur_e);
return;
}
return;
}
*pre_e = L.elem[i];
}
}
void NextElem(SqList L,ElemType cur_e,ElemType *next_e)
{
int i;
for (i = 0; i < L.length; ++i)
{
if (cur_e == L.elem[i])
{
if (i == L.length-1)
{
printf("%d位于最后一个位置,它没有后继./n",cur_e);
return;
}
*next_e = L.elem[i+1];
return;
}
}
}
void ListInsert(SqList *L,int i,ElemType e)
{
int j;
if (L->length == 0)
{
L->elem[0] = e;
++L->length;
return;
}
if (i <= 0 || i > L->length)
{
printf("ilegle position %d(i)/n",i);
return;
}
if (L->length == L->listsize)
{
L->elem = (ElemType*)realloc(L->elem,(LIST_INIT_SIZE + LISTINCREMENT) * sizeof(ElemType));
if (!L->elem)
{
exit(OVERFLOW);
}
L->listsize += LISTINCREMENT;
}
for (j = L->length-1; j >= i-1; --j)
{
L->elem[j+1] = L->elem[j];
}
L->elem[++j] = e;
++L->length;
}
void ListDelete(SqList *L,int i,ElemType *e)
{
int j;
if (i <= 0 || i > L->length)
{
printf("ilegle position.%d(i)/n",i);
return;
}
*e = L->elem[i-1];
for (j = i; i < L->length; ++i)
{
L->elem[i-1] = L->elem[i];
}
--L->length;
}
void ListTraverse(SqList L,void (*visit)(ElemType e))
{
int i;
if (L.length == 0)
{
printf("Empty List./n");
return;
}
for (i = 0; i < L.length; ++i)
{
visit(L.elem[i]);
}
}
void visit(ElemType e)
{
printf("%d ",e);
}
Status compare(ElemType lhs,ElemType rhs)
{
if (lhs == rhs)
{
return OK;
}
return ERROR;
}
int main()
{
SqList L;
int i;
ElemType e;
InitList(&L);
for (i = 0; i < 10; ++i)
{
ListInsert(&L,1,i);
}
for (i = 0; i < 10; ++i)
{
ListDelete(&L,1,&e);
}
//DestroyList(&L);
ListTraverse(L,visit);
//GetElem(L,2,&e);
//PriorElem(L,3,&e);
//NextElem(L,7,&e);
printf("/n%d",LocateElem(L,5,compare));
return 0;
}