【数据结构】线性表基本操作

一.线性结构:

定义:

若结构时非空有限集,则有且仅有一个开始节点和一个终端节点,并且所有节点最多只有一个直接前驱和一个直接后继。

表达式:(a1,a2,...,an)

特点:

1.只有一个首结点和一个尾结点;

2.除首尾结点外,其他结点只有一个直接前驱和一个直接后继

总结:

线性结构反应结点之间的关系是一对一的。线性结构包括线性表,堆栈,队列,字符串,数组等。

二.线性表

(一)线性表的类型定义

( a1 , a2 , a3 , ... , ai-1, ai , ai+1 , ... , an )

a1,an分别为线性起点和线性终点。

ai-1是ai的直接前驱,ai+1是ai的直接后继。

1,2,3,...,n 是下标,表示元素在表中的位置

n为元素总个数,即表长

【注】同一线性表中的元素具有相同特性,元素之间的关系是线性的,比如学生情况登记表。

 (二) 线性表的顺序表示和实现

1.顺序表的顺序表示

用一组地址连续的存储单元依次存储线性表中的数据元素。

( a1 , a2 , a3 , ... , ai-1, ai , ai+1 , ... , an )

a1占据线性表的起始地址,也称为基地址

2.元素地址计算方法

loc(ai)=loc(a1)+(i-1)*L。

loc表示地址,L表示该线性表中一个元素占用的存储单元*个数。

【注】计算机最小信息单位是bit(一个二进制位),8个bit组成一个byte(字节)。一个存储单元可以存储一个字节,即8个bit。

比如int型数据通常占4个字节,那么L为4。

3.顺序表主要操作的实现

#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2

typedef int Status;//int重命名为Status,表示状态,即上面宏定义的正确,错误,溢出等
typedef int Elemtype;

Elemtype是元素类型的意思,下面以int为例,也可以使用其他类型。

动态分配的顺序存储结构:

#define LIST_INIT_SIZE 100//线性表存储空间的初始分配量
#define LISTINCREMENT 10//线性表存储空间的初始分配量(空间不足时会用到)

typedef struct
{
    Elemtype *elem;//存储空间基地址
    int length;//当前表长(即现在表中的元素个数)
    int listsize;//当前分配的存储容量(以sizeof(Elemtype)(字节数)为单位)
}SqList;//将上面结构体命名为SqList

顺序表的初始化

Status InitList_Sq(SqList &L)//建空表 status即为int型变量,表示状态
{
	L.elem=(Elemtype *)malloc(LIST_INIT_SIZE*sizeof(Elemtype ));//基地址
	if(!L.elem)	exit(OVERFLOW);//存储分配失败,结束。非零值
	L.length=0;//空表长度为0
	L.listsize=LIST_INIT_SIZE;//初始存储容量
	return OK;//分配成功
}

malloc函数的原型为:void *malloc (unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的个字节的(内存块)连续空间。 以void*类型返回分配的内存区域地址(分配区域的起始地址)。

free函数原型是:void free(void *p); 其作用是释放指针p所指向的内存区。其参数p必须是先前调用malloc函数时返回的指针。

realloc函数原型为void *realloc(void *p,unsigned int size); 如果已经通过malloc函数获得了动态空间 ,想改变其大小,可以用realloc函数重新分配。用realloc函数将p所指向的动态空间的大小改变为size。

L.elem是int*类型,所以需要强制类型转化为int*,才能为它分配对应类型的地址。

!L.elem:当条件为真时,执行内容。if的内容执行,表明!L.elem为1,则L.elem为0.没有分配。

size:以字节为单位,地址也以字节为单位。LIST_ INIT_SIZE可以理解为可容纳的元素个数,元素类型为int型,那么地址大小为LIST_ INIT_SIZE*sizeof (int)。

顺序表的销毁

初始条件:顺序线性表L已存在。

操作结果:销毁顺序线性表L

Status DestroyList(SqList &L)
{
	free(L.elem);
	L.elem=NULL;
	L.length=0;
	L.listsize=0;
	return OK;
}

顺序表置空

初始条件:顺序线性表L已存在。

操作结果:将L重置为空表

Status ClearList(SqList &L)
{
	L.length=0;
	printf("长度为",L.length);
	return TRUE;
}

顺序表判空

初始条件:顺序线性表L已存在
操作结果:若L为空表,则返回1,否则返回0

Status ListEmpty(SqList &L)
{
	if(L.length==0) return 1;
	else return 0;
}

顺序表求长

初始条件:顺序线性表L已存在。

操作结果:返回L中数据元素个数

Status ListLength(SqList L)
{
	return L.length;
}

返回指定位置元素的值
初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。
操作结果:用e返回L中第i个数据元素的值

Status GetElem(SqList L,int i,Elemtype &e)
{
	printf("输入查找元素的位置:");
	scanf("%d",&i);
	if(i<1||i>L.length) return ERROR;
	e=*(L.elem+1-1);
	return OK;
}

顺序表的赋值

Status ValueList_Sq(SqList &L)//赋值
{
	int i,j;
	printf("元素个数:");
	scanf("%d",&i);//取地址别忘
	if(i>L.listsize)//元素个数大于能容纳的个数
	{
		L.elem=(Elemtype *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(Elemtype ));
        //重新分配空间。当前容量+增量
		L.listsize+=LISTINCREMENT;	
	}
	printf("输入元素:");
	for(j=0;j

【注】元素下标 ( j ) +1=位序 ( i )。

顺序表的查找:

初始条件:顺序表L已存在, compare( )是比较两个数据元素是否相等的判定函数,相等返回1,不等返回0

操作结果:返回L中第一个与e满足关系compare( )的数据元素的位序,若不存在这样的元素,返回0

Status LocateElem_Sq(SqList L, Elemtype e,Status (*compare)(Elemtype , Elemtype ))
 {
    Elemtype *p=L.elem; // p 的初值为第 1 元素的存储位置 
    int i = 1; // i 的初值为第 1 元素的位序
    printf("输入查找元素的值:");
    scanf("%d",&e);
    while (i <= L.length && !(*compare)(*p++, e))
    ++i;
    if (i <= L.length) return i;
    else return ERROR; 
}

思路:从第一个元素开始,不断比较(*(compare(当前元素,要查找的元素 ),若i <=L.length,如果没找到 !(*compare)(*p++, e),一直向后找(i++)。如果找到, !(*compare)(*p++, e)不满足,则跳出查找操作,返回位序;如果全部遍历仍没找到,返回0。

*p++:使用p取内容的值后p再加1(sizeof(int))

compare指向函数的指针,函数指针变量指向函数,函数参数类型均为int型。 在编译时,一个函数总是占用一段连续的内存区域,每个函数都有一个入口地址,函数名为该函数所在内存区域的首地址,这和数组名非常类似,把函数的这个首地址(或称为入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。

比如:

Status Equal(Elemtype a,Elemtype b)//相等关系
{
	if(a==b) return OK;
	else return 0;	
}

也可以定义其他关系,比如是否满足a

想判断什么关系,只需将表明关系的函数名(即首地址)赋给*Compare,那么它指向的就是该函数。

	printf("%d",LocateElem_Sq(List,e,Equal));

顺序表的插入

初始条件:L存在,1<=i<=L.length+1

操作结果:在表中第i个位置之前插入元素e,表长+1

Status ListInsert_Sq(SqList &L,Elemtype i,Elemtype e)
{
	Elemtype *p,*q;//p表示插入位置.p,q与L.elem同类型的指针
    Elemtype *newbase;//新分配内存地址
	
    printf("输入要插入的位置和元素的值:");
	scanf("%d%d",&i,&e);
	
    if(i<1||i>L.length+1) exit(OVERFLOW);//插入位置不合法
    
	if (L.length >= L.listsize) 
	{// 当前存储空间已满,增加分配
    	newbase = (Elemtype *) realloc (L.elem, (L.listsize+LISTINCREMENT)*sizeof (Elemtype ));
    	if (!newbase) exit(OVERFLOW); // 存储分配失败
    	L.elem = newbase; // 新基址
    	L.listsize += LISTINCREMENT; // 增加存储容量
	}
    p=&(L.elem[i-1]);//取地址
	for(q=&L.elem[L.length-1];q>=p;q--) //长度-1表示当前最后一个元素的下标
	*(q+1)=*q;//前一个元素值赋给后一个,实现元素顺次后移
   
    *p=e;//给插入元素赋值
	++L.length;//别忘了长度+1
	return OK;
}

思路:

(1)判断插入位置和是否合法,合法值1≤i≤L.length+1;

(2)判断顺序表的存储空间是否已满( L.length >= L.listsize );

(3)将原表第n至第i 位的元素依次向后移动一个位置,空出第i个位置;

(4)将插入元素放入第i位,表长+1;

指针p确定插入位置为i,反映在数组中下标为i-1,由此确定p值;

q指向要后移的元素。初值为末尾元素地址,*(q+1)为空,从n位到i位依次后移,总有预留空位,避免覆盖;相反就会丢失数据。直到第i个元素移动完毕(q>=p,不要忘记等于,不然第i个元素未被后移)。现在*p就为空,刚好给它赋值,实现插入。

顺序表的删除

初始条件:L存在,1<=i<=L.length

操作结果:删除表中第i个元素,用e返回其值,表长-1

Status ListDelete(SqList &L,int i,Elemtype &e) 
{
    Elemtype *p,*q;
    printf("输入删除元素的位置:");
    scanf("%d",&i);
    if(i<1||i>L.length) // i值不合法
    exit(OVERFLOW);
    p=L.elem+i-1; // p为被删除元素的位置,也可以写p=&(L.elem[i-1]); 
    e=*p; // 被删除元素的值赋给e 
    q=L.elem+L.length-1; // 表尾元素的位置 
    for(++p;p<=q;++p) // 被删除元素之后的元素左移。起始为待删除元素的下一位,终止于最后一位元素。
    *(p-1)=*p;
    printf("删除元素的值为%d",e);
    L.length--; // 表长减1
    return OK;
}

顺序表的输出

Status PrintList_Sq(SqList &L)//输出
{
	int i;
	printf("List:");
	for(i=0;i

整体实现:

#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
 
typedef int Status;//int重命名为Status,表示状态,即上面宏定义的正确,错误,溢出等
typedef int Elemtype;
#define LIST_INIT_SIZE 100//线性表存储空间的初始分配量
#define LISTINCREMENT 10//线性表存储空间的初始分配量(空间不足时会用到)
 
typedef struct
{
    Elemtype *elem;//存储空间基地址
    int length;//当前表长(即现在表中的元素个数)
    int listsize;//当前分配的存储容量(以sizeof(Elemtype)(字节数)为单位)
}SqList;//将上面结构体命名为SqList

Status InitList_Sq(SqList &L)//建空表 status即为int型变量,表示状态
{
	L.elem=(Elemtype *)malloc(LIST_INIT_SIZE*sizeof(Elemtype ));//基地址
	if(!L.elem)	exit(OVERFLOW);//存储分配失败,结束。非零值
	L.length=0;//空表长度为0
	L.listsize=LIST_INIT_SIZE;//初始存储容量
	return OK;//分配成功
}

Status DestroyList(SqList &L)
{
	free(L.elem);
	L.elem=NULL;
	L.length=0;
	L.listsize=0;
	return OK;
}

Status ClearList(SqList &L)
{
	L.length=0;
	printf("长度为",L.length);
	return TRUE;
}

Status ListEmpty(SqList &L)
{
	if(L.length==0) return 1;
	else return 0;
}

Status ListLength(SqList L)
{
	return L.length;
}

Status GetElem(SqList L,int i,Elemtype &e)
{
	printf("输入查找元素的位置:");
	scanf("%d",&i);
	if(i<1||i>L.length) return ERROR;
	e=*(L.elem+1-1);
	return OK;
}

Status ValueList_Sq(SqList &L)//赋值
{
	int i,j;
	printf("元素个数:");
	scanf("%d",&i);//取地址别忘
	if(i>L.listsize)//元素个数大于能容纳的个数
	{
		L.elem=(Elemtype *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(Elemtype ));
        //重新分配空间。当前容量+增量
		L.listsize+=LISTINCREMENT;	
	}
	printf("输入元素:");
	for(j=0;jL.length+1) exit(OVERFLOW);//插入位置不合法
    
	if (L.length >= L.listsize) 
	{// 当前存储空间已满,增加分配
    	newbase = (Elemtype *) realloc (L.elem, (L.listsize+LISTINCREMENT)*sizeof (Elemtype ));
    	if (!newbase) exit(OVERFLOW); // 存储分配失败
    	L.elem = newbase; // 新基址
    	L.listsize += LISTINCREMENT; // 增加存储容量
	}
    p=&(L.elem[i-1]);//取地址
	for(q=&L.elem[L.length-1];q>=p;q--) //长度-1表示当前最后一个元素的下标
	*(q+1)=*q;//前一个元素值赋给后一个,实现元素顺次后移
   
    *p=e;//给插入元素赋值
	++L.length;//别忘了长度+1
	return OK;
}

Status ListDelete(SqList &L,int i,Elemtype &e) 
{
    Elemtype *p,*q;
    printf("输入删除元素的位置:");
    scanf("%d",&i);
    if(i<1||i>L.length) // i值不合法
    exit(OVERFLOW);
    p=L.elem+i-1; // p为被删除元素的位置,也可以写p=&(L.elem[i-1]); 
    e=*p; // 被删除元素的值赋给e 
    q=L.elem+L.length-1; // 表尾元素的位置 
    for(++p;p<=q;++p) // 被删除元素之后的元素左移。起始为待删除元素的下一位,终止于最后一位元素。
    *(p-1)=*p;
    printf("删除元素的值为%d",e);
    L.length--; // 表长减1
    return OK;
}

Status PrintList_Sq(SqList &L)//输出
{
	int i;
	printf("List:");
	for(i=0;i

运行结果

【数据结构】线性表基本操作_第1张图片

有错还请多多指教,感谢 

你可能感兴趣的:(数据结构)