数据结构知识整理-线性表篇(已完结)

本文详细介绍了线性表的两种常见实现——顺序表和单链表,包括它们的特点、C语言描述及PTA例题解析。顺序表支持随机存取但插入删除操作代价高,单链表则相反。文中还讨论了在特定操作下哪种存储方式更节省时间,并给出了相关算法的时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


寻寻寻寻20.11.30更新:
1.增加PTA部分线性表例题。
2.增加顺序表特点描述。


一、顺序表;

(1)特点:

顺序存储,随机存取(就是通过首地址和元素的位序号值可以在O(1)的时间内找到指定的元素。);
读取数据方便,插入和删除将会移动较多的数据(时间复杂度高)。

(2)C语言描述:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define MAX_SIZEL 1000
#define ElemType int
#define Status int
#define OK 1
#define OVERFLOW -1
#define ERROR 0
#define INCERMENT 10
using namespace std;
typedef struct{
	ElemType *elem;//储存空间基址;
	int length;//当前长度 
	int listsize;//目前容量 
}SqList;

//初始化

Status InitList_Sq(SqList &L){
	//初始化顺序表。 
	L.elem=new ElemType[MAX_SIZEL];
	if(!L.elem)exit(OVERFLOW);
	L.length=0;
	L.listsize=MAX_SIZEL;
	return OK;
}

//读取元素

Status GetElem(SqList &L,int i,ElemType&e){
	//获取L中第i个元素并用e去返回。
	if(i<1||i>L.length)return ERROR;//元素不存在
	e=L.elem[i-1];
	return OK; 
} 

//指定位置插入元素

Status ListInsert(SqList& L,int i,ElemType e){
	//在顺序表第i个元素前插入元素e;
	 //判断表满
	 ElemType* newbase;	 
	 if(i<1||i>L.length+1)return ERROR;
	 if(L.length>=L.listsize){
	 	newbase=(ElemType*)realloc(L.elem,(L.length+INCERMENT)*sizeof(ElemType));
	 	if(!newbase)exit(OVERFLOW);
	 	L.elem = newbase;
		 L.listsize+=INCERMENT; 
	 } 
	 ElemType *q,*p;
	 q=&(L.elem[i-1]);
	 for(p=&(L.elem[L.length-1]);p>=q;p--){
	 	*(p+1)=*p;
	 }
	 *p=e;
	 ++L.length;
	 return OK;
}

//删除元素


Status ListDelete_Sq(SqList &L,int i,ElemType &e){
	if(i<1||i>L.length)return ERROR;
	ElemType* q,*p;
	p=&(L.elem[i-1]);//获取删除位置元素;
	e=*p; 
	q=L.elem+L.length-1;
	for(++p;p<=q;++p){
		*(p-1)=*p;
	} 
	--L.length;
	return OK;
}

二、单链表

(1)特点

随机储存,顺序读取;逻辑上相邻,储存物理位置不相邻。
为操作方便统一,常常在第一个结点前加一个头节点,指向首结点

(2)C语言描述
#include <stdio.h>
#include <stdlib.h>
#define ElemType int
#define Status int 
#define ERROR 0
#define OK 1
typedef struct LNode{
	ElemType date;
	struct LNode *next;
}LNode,*LinkList;

//结点初始化


void InitLink_L(LNode *p){
	p=(LNode*)malloc(sizeof(LNode));
	p->date=0;
	p->next=NULL;
}

//获取结点数据


Status GetElem_L(LinkList L,int i,ElemType &e){
	//L是单链表的头指针以e返回第i个元素的值;
	LinkList P;int j;
	P=L->next; j=1;
	while(P&& j<i){
		P=P->next;
		j++; 
	}
	if(P||j>i)return ERROR;
	e = P->date;
	return OK;
}

//在指定位置插入节点


Status ListIncert_L( LinkList &L,int i,ElemType &e){
	//L为带头节点的链表的头指针。
	//在i的位置插入元素e
	LinkList p=L;int j=0;
	while(p&&j<i-1){
		p=p->next;++j;//寻找第i个节点; 
	}
	if(!p) 
	 return ERROR;
	 LNode* s;
	 InitLink_L(s);
	 s->date=e;
	 s->next=p->next;
	 p->next=s; 
	return OK;
}

//删除指定位置的结点

Status DeletList(LinkList &L,int i,ElemType &e){
	LinkList p=L;int j=0;
	while(p->next&&j<i-1){
		p=p->next;
		++j;
	}
	if(!p->next)return ERROR;
	e=p->date;
	LNode* a;
	a=p->next;//设a中介结点的必要性是释放内存,防止内存泄漏; 
	p->next=a->next;
	free(a);
	return OK; 
}

三、有序表与无序表的应用

内容较为简单,只转载ppt
在这里插入图片描述

四、PTA例题

(1)顺序表

1、若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用哪种存储方式最节省时间?
A.双链表
B.单循环链表
C.带头结点的双循环链表
D.顺序表

由顺序表特点可较易得,D更合适。

2、要将一个顺序表{a​0,a1,a2……an-1}中数据元素ai(0≤i≤n-1,这是第i+1个数据)删除,需要移动( )个数据元素。

删除第i个元素后,之后的元素是从ai+1到an-1,两者之间的元素易得出 n - i -1。

3、若长度为n的线性表采用顺序结构,在第i个数据元素之前插入一个元素,需要它依次向后移动()个元素。

在第i个元素前插入一个元素,则需要移动的元素为从第i到第n,不动的元素个数有i-1个,所以需要向后移动n-i+1个元素。

4、线性表L=(a1, a2 ,……,an )用一维数组表示,假定删除线性表中任一元素的概率相同(都为1/n),则删除一个元素平均需要移动元素的个数是()。

依次分析,需要移动的个数分别为:n-1,n-2,n-3,…… ,0,又是一个公差为1的等差数列,但我们只需要求出他的平均值为(n-1)/2。

(2)单链表

1、设h为不带头结点的单向链表。在h的头上插入一个新结点t的语句是:t->next=h; h=t;

主要是不带头结点,注意别错了。

2、将长度为n的单链表连接在长度为m的单链表之后的算法的时间复杂度为( )。

答案:O(m),注意需要遍历m次在连接。

3、对于一非空的循环单链表,h和p分别指向链表的头、尾结点,则有:p->next == h

注意区分首结点、头结点。没啥好说的,仔细认真。

4、在双向循环链表结点p之后插入s的语句是:
s->prior=p; s->next=p->next; p->next->prior=s; p->next=s;

5、非空的循环单链表head的尾结点(由p所指向)满足(p->next == head)。

前提是head为头结点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值