用C语言的一维数组实现线性表的顺序存储

Python013

用C语言的一维数组实现线性表的顺序存储,第1张

还是说只要是在内存中申请了一块连续的地址空间存储数据只要知道其首地址都可以用数组的形式访问其中的元素呢?

就是这样的。

线性表的特点就是长度可变,如果使用常规的数组,就不能实现这个特性,因为数组是定长的。而在堆中申请的内存可以通过参数在运行时指定它的大小,且可以调整它的大小,并且其使用方式和数组一样,使用索引访问。

int*p = (int*)malloc(sizeof(int)*5)

p[0] //第一个元素

p[1] //第二个元素

p[2] //第三个元素

//...

free(p)

链表

1。是由结构体和指针构成的。

2。包括两个部分一个是数据域和指针域。

3。链表中的结点分为两类:头结点和一般结点。头结点是没有数据域的。

4。基本操作有:初始化链表,增加结点和删除结点,求链表的长度等等。

struct Linknode{

int data

struct Linknode *next

}

这个地方有个知识点:这个是链表的数据结构是有结构体和指针构成。结构体名为Linknode.但这里面没有定义结构体变量,只有我们定义了结构体变量才能使用结构体。

结构体变量怎么定义呢?

有两种方式:

1。struct Linknode Linklist

2.typedef struct linknode Linklist.

一般我们都希望采用第2种,这样的好处是: 当我们再定义结构体变量时,可以用:Linklist p而如果我们采用第一种还必须采用 struct Linknode p对比一下就可以知道第2种要简单很多。那么下面我们都采用第2种方式来定义结构体变量。

上面我们已经定义了一个链表:

1。初始化链表。

#include

#include

int InitLinkList(Linklist **Lnode)

{

*Lnode=(Linklist)malloc(sizeof(Linklist))//*Lnode等于L,对与*Lnode的分配空间相当与对主函数中的L分配空间。

if(!*Lnode)

return 0

(*Lnode)->next=NULL

}

在初始化链表的时候,我们用到了2级指针为什么呢?因为我们希望在InitLinkList函数生成的头结点,主函数中也能指向这个头结点。如果我们用一级指针的话,用malloc分配空间的时候,它将会返回分配空间的首地址给指针变量Lnode,而不能使是的空间被主函数中指针变量L得到这个地址。所以我们要用2级指针。

void main()

{

Linklist *L

InitLikList(&L)

}

2。增加链表结点

增加链表结点其实很简单,一般用到三个结构体指针变量和一个循环结构。

InsertLinkList(Linklist *Lnode)

{

Linklist *p,*q

int d

{

scanf("%d",&d)

if(d==-9999)

break

p=Lnode->next//p指向头结点

//通过while循环和指针变量p定位要插入的结点q的位置。

while(p)

p=p->next

//生成一个要插入的结点

q=(Linklist)malloc(sizeof(Linklist))//申请要插入的结点空间

q->data=d//填充要插入结点的数据域

q->next=p->next//首先填充要插入结点q的指针域进行填充。

p->next=q//然后把定位好的p指针域进行修改指向q.

}while(9)//循环退出的条件是输入的数据-9999

}

void main()

{

Linklist *L

InitLinkList(&L)//生成一个头结点

InsertLinkList(L)//插入结点

}

3。求链表的长度:

int LengthLinkList(Linklist *Lnode)

{

int i=0

Linklist *p

p=Lnode->next//p指向链表的第一个结点。

while(p)

{

i++

p=p->next

}

return i

}

void main()

{

Linklist *L

InitLinkList(&L)//生成一个头结点

InsertLinkList(L)//插入一个结点

LengthLinkList(L)//求链表的长度。

}

4.删除结点

删除链表结点其实很简单,一般用到三个结构体指针变量和一个循环结构。

DestroyLinkList(Linklist *Lnode)

{

Linklist *p,*q

p=Lnode//p指向链表的头结点

while(p)

{

q=p->next//q指向当前结点的下一个结点。

free(p)//释放当前结点

p=q//p指向下一个结点

}

}

void main()

{

Linklist *L

InitLinkList(&L)//生成一个头结点

InsertLinkList(L)//插入结点

LengthLinkList(L)//求链表的长度。

DestroyLinkList(L)//删除链表结点

}

直接上源码吧。

/*线性表功能的实现*/

#include<stdio.h>

//定义常量 存储空间的初始化分配

#define MAXSIZE 20

#define TRUE 1

#define ERROR -1

#define FALSE 0

#define OK 1

//用typedef定义类型

typedef int Status

typedef int ElemType

//定义一个结构体类型

typedef struct{

ElemType data[MAXSIZE]

int length

} SqList

//初始化函数

Status initList(SqList *L){

L->length = 0

return OK

}

//返回线性表的长度

Status getListLength(SqList L){

return L.length

}

//线性表为空返回true,否则返回false

Status listEmpty(SqList L){

if(L.length == 0){

return TRUE

}

return FALSE

}

//线性表清空,长度为0

Status clearList(SqList *L){

L->length = 0

return OK

}

//获取指定的元素的值,返回下标为i - 1的元素,赋值给e

Status getElem(SqList L, int i, ElemType *e){

//判断元素位置是否合法[i]

if(i >L.length || i <1){

printf("查找的位置不正确 \n")

return ERROR

}

//判断线性表是否为空

if(listEmpty(L)){

return ERROR

}

*e = L.data[i - 1]

return OK

}

//在线性表中查找指定的e相等的元素,如果查找成功,返回该元素的下标,否则返回ERROR

Status locateElem(SqList L, ElemType e){

int i

for(i = 0i <L.length - 1i++){

if(L.data[i] == e){

return i

}

}

printf("没有查找到元素 %d 指定的下标\n",e)

return ERROR

}

//自动创建 MAXSIZE 个元素,并赋值为0

Status createList(SqList *L){

int i

for(i = 0i <10i++){

L->data[i] = 0

}

L->length = 10

return OK

}

//在线性表中第i个位置前插入新元素e

Status listInsert(SqList *L, int i, ElemType e){

//判断长度是否可以允许插入新的数据

if(L->length >= MAXSIZE){

printf("空间已满,不能再插入数据\n")

return FALSE

}

//判断插入位置的合法性

if(i <1 || i >L->length) {

printf("插入位置不正确\n")

return FALSE

}

int j

for(j = L->length - 1j >= ij--){

L->data[j] = L->data[j - 1]

}

L->data[i - 1] = e

L->length++

return TRUE

}

//删除线性表中第i个元素,成功后表长减1,用e返回其值

Status deleteList(SqList *L, int i, ElemType *e){

//判断线性表是否为空

if(listEmpty(*L)){

return ERROR

}

//判断删除的位置是否合法

if(i <1 || i >L->length) {

printf("删除位置不合法\n")

return ERROR

}

*e = L->data[i - 1]

for(ii <L->lengthi++){

L->data[i - 1] = L->data[i]

}

L->length--

return TRUE

}

//遍历线性表

Status listTraverse(SqList L){

int i

for(i = 0i <L.lengthi++){

printf("%d ",L.data[i])

}

printf("\n")

return OK

}

//主程序

int main(void){

SqList L

ElemType e

initList(&L)

int option = 1

int input_number

int res

ElemType input_value

printf("\n1.遍历线性表 \n2.创建线性表 \n3.清空线性表 \n4.线性表插入 \n5.查找表中元素 \n6.判断元素是否在表中 \n7.删除某个元素 \n8.线性表长度\n9.线性表是否为空\n0.退出 \n请选择你的操作:\n")

while(option){

scanf("%d",&option)

switch(option){

case 0:

return OK

break

case 1:

listTraverse(L)

break

case 2:

createList(&L)

listTraverse(L)

break

case 3:

clearList(&L)

listTraverse(L)

break

case 4:

printf("请输入插入的位置:")

scanf("%d",&input_number)

printf("\n")

printf("请输入插入的值:")

scanf("%d",&input_value)

printf("\n")

listInsert(&L, input_number, input_value)

listTraverse(L)

break

case 5:

printf("请输入要查找的位置:")

scanf("%d",&input_number)

printf("\n")

getElem(L, input_number, &input_value)

printf("第%d个元素的值为:%d\n",input_number,input_value)

break

case 6:

printf("请输入要查找的元素:")

scanf("%d",&input_value)

printf("\n")

res = locateElem(L, input_value)

if(res != ERROR){

printf("值为%d在表中的第%d个位置\n",input_value,input_number)

}

break

case 7:

printf("要删除第几个元素?")

scanf("%d",&input_number)

printf("\n")

deleteList(&L, input_number, &input_value)

listTraverse(L)

break

case 8:

res = getListLength(L)

printf("线性表的长度是:%d",res)

break

case 9:

res = listEmpty(L)

if(res){

printf("线性表的是空的")

}else{

printf("线性表的是不是空的")

}

break

}

}

return OK

}

线性表的特征是:

1. 元素之间是有序的,如果元素存在多个,则第一个元素无前驱,最后一个无后继,其它元素都有且只有一个前驱和后继.

2. 元素个数是有限的. 当n=0是,称为空表

线性表实现方式有两种,分别是顺序存储结构和链式存储结构,它们之间各有优缺点 . 根据需求的不同进行选择不同的存储结构.

线性表存储结构的优缺点

优点:

1. 无须为表中元素之前的逻辑关系而增加额外的存储空间

2. 可以快速的存取表中的任一位置的元素

缺点:

1. 插入和删除操作需要移动大量元素

2. 当线性表长度变化较大时,难以确定存储空间的容量.

3. 造成存储空间的”碎片”.