数据结构2.1 线性表及其实现

线性表的抽象数据类型描述

操作集:线性表∈List,元素X∈ElementType,线性表的基本操作有:

  • List MakeEmpty () :初始化空线性表
  • ElementType FindKth ( int k, List l )
  • int FindElement ( Element x, List l)
  • void InsertElement ( Element x, int i, List l)
  • void DeletElement ( int i, List l)
  • int getLength ( List l)

线性表的线性存储方式

线性表的顺序存储实现

typedef struct LNODE *List;
struct LNODE {
	ElementType Data[MAXSIZE];
	int last;//表示线性表的最后一个元素 
}; 
struct LNODE l;
List PtrL;
//访问下标为i的变量 l.Data[i] / PtrL -> Data[i] 
//返回线性表的长度 l.last + 1 / Ptrl -> last + 1

主要操作的实现

1.初始化(创建空的线性表)

//初始化线性表(建立空的顺序表)
List MakeEmpty() {
	List Ptrl;
	Ptrl = (List) malloc (sizeof (struct LNODE));
	Ptrl -> last = -1;
	//last = 0表示指向第一个元素,last = -1表示没有元素
	return Ptrl;
} 

2.查找

int Find(ElementType x,List l) {
	int i = 0;
	while(i <= Ptrl->last && Ptrl->Data[i] != x)	i++;
	if(i > Ptrl->last)	return -1;//没找到,返回-1 
	else return i;//找到,返回其位置 
	//查找成功的平均比较次数为 (n+1)/2 ,时间性能O(n)
}

3.插入

void Insert( List L, ElementType X, int i) { /* 在L的指定位置i前插入一个新元素X */
    if ( L->Last == MAXSIZE-1) {    /* 表空间已满,不能插入 */
        printf("表满"); 
        return; 
    }  
    if ( i<0 || Ptrl -> Last+1 ) { /* 检查插入位置的合法性 */
        printf("位置不合法");
        return; 
    } 
    //从后往前移 
    /*如果把后移数组元素的循环改为for ( j = i-1; j <= PtrL->Last; j++ )   PtrL->Data[j+1]=PtrL->Data[j];
   则Data[i-1]到Data[Ptrl -> last]均为原来的Data[i-1]*/ 
    for( j = L->Last; j>=P; j-- )
        L->Data[j+1] = L->Data[j]; /* 将位置P及以后的元素顺序向后移动 */
    L->Data[i] = X;  /* 新元素插入 */
    L->Last++;       /* Last仍指向最后元素 */
    return; 
    //平均移动次数n/2 时间复杂度O(n) 
} 

4.删除

/* 删除 */
void Delete( List L, int i ) { /* 从L中删除指定位置P的元素 */
    if( i < 0 || i > L->Last ) { /* 检查空表及删除位置的合法性 */
        printf("位置%d不存在元素", i ); 
        return; 
    }
    for( int j = i+1; j <= L->Last; j++ )
        L->Data[i-1] = L->Data[i]; /* 将位置P+1及以后的元素顺序向前移动 */
    L->Last--; /* Last仍指向最后元素 */
    return;   
    //平均移动次数(n-1)/2 时间复杂度O(n)
}

线性表的链式存储实现

主要操作的实现

1.求表长

/*求表长*/
int getLength(List Ptrl) {
	List p = Ptrl;//p指向表的第一个结点 
	int j = 0;
	while(p) {//循环条件:p != NULL 即链表未结束 
		p = p -> Next;
		j++;//当前p指向第j个结点 
	}
	return j;
	//时间复杂度O(n) 
}

2.查找
(1)按序号找

List FindKth (int K, List Ptrl) {
	List p = Ptrl;//将p赋为表头
	int i = 1;
	while(p != NULL && i < k) {
		p = p -> Next;
		i++;
	}
	if(i==k)	return p;//返回指针 
	else	return NULL;
} 

(2)按值查找

Lis Find(ElementType x, List Ptrl) {
	List p = Ptrl;//将p赋为表头 
	while(p!=NULL && p->Data != x)
		p = p -> Next;
	return p;
} 

3.插入(在第i-1个结点后插入一个值为x的新结点)
①构造一个新的结点,用s指向
②找到链表的第i-1个结点,用p指向
③修改指针,插入结点(p之后插入新结点是s)
若两个赋值语句顺序交换,则p -> Next 指向p,故不能正确完成插入

List insert(ElementType x, int i, List Ptrl) {
	List p,s;
	if( i==1 ) {								//新结点插在表头上 
		s = (List)malloc(sizeof(struct LNode));	//申请、填装新结点 
		s -> Data = x;
		s -> Next = Ptrl;
		return s;								//返回新表头指针 
	}
	p = FindKth(i-1, Ptrl);						//查找第i-1个结点 
	if( p == NULL ) {							//第i-1个结点不存在,不能插入 
		printf("参数报错");
		return NULL;
	}
	else {
		s = (List)malloc(sizeof(struct LNode));	//申请、填装结点 
		s -> Data = x;
		s -> Next = p -> Next;					//新结点插入在第i-1个结点后面 
		p -> Next = s;
		return Ptrl;
	}
}

4.删除
①找到链表的i-1个结点,用p指向
②用s指针指向要被删除的结点
③修改指针,删除s指向的结点
④释放s所指结点的空间

List Delete(int i, List Ptrl) {
	List p,s;
	if( i==1 ) {//要删除的是表的第一个结点 
		s = Ptrl;//s指向第一个结点 
		if(Ptrl != NULL)	Ptrl = Ptrl -> Next;//冲链表中删除 
		else return NULL;
		free(s);//释放被删除结点 
		return Ptrl;
	}
	p = FindKth(i-1, Ptrl);//查找第I-1个结点 
	if( p == NULL){
		printf("第%d个结点不存在",i-1);
		return NULL;
	}
	else if(p->Next == NULL) {
		printf("第%d个结点不存在",i);
		return NULL;
	}
	else {
		s = p -> Next;//s指向第i个结点 
		p -> Next = s -> Next;//从链表中删除 
		free(s);//释放被删除结点 
		return Ptrl;
	}	
}

广义表与多重链表

广义表

线性表的推广
广义表中的元素可能是单元素也可能是另一个广义表

//广义表的构建
typedef struct GNode *Glist;
struct GNode{
	int Tag;				//标志域,0表示结点是单元素,1表示结点是广义表 
	union {					//子表指针域Sublist与单元素数据域Data复用,即公用存储空间 
		ElementType Data;
		GList SubList;
	} GRegion;
	GList Next;				//指向后继结点 
};

多重链表

链表中的某个结点可能隶属于多个链表

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值