数据结构-线性表

线性表

2.1线性表的基本概念与实现

1.定义:线性表是具有相同特性数据元素的一个有限序列。该序列种所含元素的个数叫做线性表的长度,用n(n>=0).注意:n可以等于0,表示线性表可以是空表

特性:

有限序列

线性表元素的相同特性

可以是有序也可以是无序

2.逻辑特性:

表头元素没有前驱

表位元素没有后继

其他元素均有一个直接前驱,一个直接后继

3.线性表的存储结构

顺序表:顺序存储结构

顺序表就是把线性表中的所有元素按照一定逻辑关系,一次粗唇到从指定的存储位置开始一块连续的存储空间中。

第一个元素的存储位置就是指定存储位置,第 i +1个元素的存储位置紧接在第 i 个元素的存储位置的后面

链表 :链式存储结构

在链表存储中,每个节点不仅包含所存元素的信息,还包含了元素之间逻辑关系的信息,

如单链表种前驱节点包含后续节点的地址信息,这样就可以通过前驱节点中的地址信息找到后续节点的位置

特性/比较:

顺序表:

①随机访问特性

②存储预先分配,且占用一整块连续的空间

③有些移动元素需要整体迁移

链表 :

①不支持随机访问

②支持存储空间的动态分配

③进行插入删除无需移动元素

④带有指针,且可能存在头结点

链表细分:

单链表

①带头节点的单链表种,头指针head指向节点,头结点的至于不含任何信息,从头结点的后续节点开始存储数据信息。

②不带头节点的单链表的头指针head直接执行开始节点,即图2-2中的结点A1

注意:头指针head始终不为空 ,head->next==NULL时候,链表为空

注意:在题目中要区分头结点和头指针,不论是带头结点的链表还是不带头结点的链表,头指针都指向链表中第一个结点,

即图2-2中的head指针;二头结点是带头结点的链表的第一个结点,只作为链表存在的标志

双链表

双链表就是在单链表结点上增添一个指针域,指向当前节点前驱。这就可以方便地由其后续来找到其前驱,从而实现输出终端结点到开始结点的数据序列。

同样的双链表也分带头结点的双链表和不带头结点的双链表,情况类似单链表

注意:带头结点的双链表,当head->next=NULL时链表为空

注意:不带头结点的双链表,当head==NULL时链表为空

循环单链表

只要将单链表的最后一个指针域(空指针)指向链表中的第一个结点即可(这里之所以说第一个结点而不是说头结点的原因:

如果循环链单链表是带头节点的,则最后一个结点的指针域要指向头结点)

注意:带头节点的循环单链表,当head==head->next时,链表为空

注意:不带头节点的循环单链表 ,当head==NULL时,链表为空

分支主题

循环双链表

和循环单链表类似,循环双链表的构造源自双链表,即将终端结点的next指针指向链表中的第一个结点,将链表中第一个结点的prior指针指向终端结点,

如图2-5所示。循环链表仍然有带头结点不带头结点之分。

注意 :不带头结点的循环双链表,当head==NULL时,不带头结点的循环双链表为空

注意:带头节点的循环双链表中是没有空指针的,其空状态如下head->next==head ; head->prior=head ;二选一作为检查就可以了

分支主题

静态链表

图2-7中的作图时静态链表,右图时其对应的一般链表。一般链表节点空间来自于整个内存,静态链表则来自一个结构体数组。

数组中的每一个结点含有两个分量

数据元素分量data

指针分量

指示了当前结点的直接后续结点在数组中的位置(这和一般链表中的next指针的地位时同等的)

注意:静态链表哦中的指针不是我们通常说的C语言中用来存储内存地址的指针型变量,而是一个存储数组下表的整形变量,

通过它可以找到后续结点的在数组中的位置,其功能类似于真的指针,因此称其为指针

即要移动近一半的元素,由此可知,插入和算出算法的平均时间复杂度为0(n)

总之两者最明显的区别是,带头结点的单链表有一个结点不存储信息(仅存储一些描述链表属性的信息,如表长),

只是作为标志,而不殆头节点的单链表的所有结点都存储信息

说明:在考研中经常要考到顺心表和链表的比较,这里是一个比较全面的答案。

基于空间的比较

1)存储分配的方式:

顺序表的存储空间是一次性分配的,莲表示存储空间是多次分配的。

2)存储密度(存储密度=结点至于所占的存储量/结点结构所占的存储总量):

顺序表的存储密度=1,链表的存储密度<1(因为结点中有指针域)

基于时间的比较

1)存储方式:

顺序表可以随机存储,也可以顺序存储(对于顺序表,一般只答随机存储就可以了);

链表只能顺序存储(所谓的顺序存储,以读取为例,要读取某个元素必须遍历其之前的所有元素才能找到它并读取)

2)插入/删除时移动元素的个数:

顺序链表平均需要移动近一半的元素

链表不需要移动,只需要修改指针

对于顺序表进行插入和删除算法的时间复杂度分析

例题:具有n个元素的顺序表(见图2-8),插入一个元素所进行的平均移动个数为多少(这里假设新元素仅插入在表中每个元素之后)

解析:因为题目要平均移动个数,这就是告诉我们要计算移动个数的数学期望,对于本体要计算期望,

就要知道在素有可能的位置插入元素所对应的元素移动个数以及在每个位置法神观察入操作的概率。

①求概率

插入的位置是随机的,所以所有的位置都有可能被插入,有n个可插入位置,所以任何一个位置被插入元素的概率都为 p = 1/n

②求对应每个插入位置需要移动的元素个数

假设要把新元素插入在表中第 i 个元素之后,则需要将第 i 个元素之后的所有元素往后移动一个位置,音痴移动元素个数为 n - i

由①和②可知,移动元素个数的期望E

E=p* {[(n)∑(i=1)] (n-1)}=(n-1)/2

删除操作时,元素平均移动的次数的计算方法与插入操作类似

2.2线性表的结构体定义和基本操作

2-2-1线性表的结构体定义

如左图所示,一个顺序表包括一个存储表中元素的数组data[]和一个只是元素个数的变量length

说明:在考试中用的最多顺序表的定义并不是讲到的结构型定义,而是这个形式:

int A[maxsize];

int n;

上边这两句就定义了一个长度为n,表内元素为整数的顺序表。显然在答卷的时候这种定义方法要比定义结构体简洁一些。

单链表结点定义

双链表结点定义

说明:

结点是内存中一片由用户分配的存储空间 ,只有一个地址来表示它的存在,没有显式的名称,因此我们会在分配链表结点空间的时候,同时定义一个指针,来储存这边空间的地址(这个过程通俗地讲叫指针指向结点),并且常用这个指针的名称来做结点的名称。

例子

LNode *A=(LNode*)malloc(sizeof(LNode));

用户分配了一片LNode型空间,月就是够着了一个LNode型结点,这时候定义一个名字为A指针来指向这个结点,同时我们吧A也当做这个结点的名字。注意,这里A命名两个东西:一个是结点,另一个是指向这个结点的指针。

本书如果出现此类描述:"p指向q",此时p指代指针,因为p即是指针名又是结点名,但是结点不能指向结点,因为p指代指针。又如“用函数free()释放p的空间”,此时p指代结点,因为p即是指针名又是结点名,但指针变量自身所需的存储空间是系统分配的,不需要用户调用函数free()释放,只有用户分配的存储空间才需要用户自己来释放,所以p指代结点。

说明:以上就是本章所需的所有的数据结构的C语言描述,希望考生牢记并且可以默写,这是完成本章程序设计题目所必须掌握的最基本的知识。

2-2-2顺序表的操作

说明:这一部分现将例题,然后从例题中总结出考研所需要的基本知识点

2-1:一直一个顺序表L其中的元素递增有序排列,设计一个算法,插入一个元素x(x为int型)后保持该序列扔递增有序排列(假设插入操作总嗯呢该成功。)

分析:有倜然可以指,解决本题,需要完成两个操作

1)找出可以让寻鼠标保持有序的插入位置。

2)将步骤1)中找出的位置以后其后的元素往后移动一个位置,然后将x放置腾出的位置上。

执行过程如图

操作一:因为顺序表L中的元素是递增排列的,所以可以从小到大逐个扫描表中元素 ,当找到第一个比x大的元时,将x插在这个元素之前即可。

如2-12所示,12位要插入元素,从左网友组个进行比较,当扫描到13的时候,发现13是第一个比12大的数,因此12应插在13前

由此可以写出一下函数,本函数返回第一个比x大的元素的位置

操作二:找到插入位置之后,将插入位置及其以后的元素醒后移动一个元素即可。有两种移动方法:

先移动最右边的元素:应该选择这种

先移动最左边的元素:很显然这种是错误的,因为会覆盖掉右边的元素

本例题体现了考研中顺序表算法部分要求掌握的两个知识点

(1)按元素值的查找算法

在顺序表中查找第一个值等于e的元素(与上题中的第一个比x大的元素是同样的道理),并返回其下标,也就是位置。代码如下

int findElem(Sqlist L, int e)

{

int i;

for (i = 0; i <= L.length; i++)

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

return i; //如果找到了 返回下标

return -1; //没有找到 就返回-1 作为失败的标志

}

(2)插入数据元素的算法

在顺序表L的p(0<=p<=length)位置上插入新的元素e。如果p的输入不正确,则返回(),代表拆失败;如果p的输入正确,

则将顺序表第p个元素及后元素右移一个位置,腾出一个空位置插入新的元素,顺序表长度 +1 ;插入操作成功,返回 1;

int insertElem(Sqlist& L, int p, int e)//L的性质本身要发生改变,所以要用引用型 加上&

{

int i;

if (p<0 || p>L.length || L.length == maxsize) //判断插入位置是否正确,或表长已经达到分配空间的最大值

return 0; //顺序表的最大允许值,此时插入不成功,返回0

for (i = L.length - 1; i > pp; --i)

L.data[i + 1] = L.data[i]; //逐个后置一个位置,直到腾出p的位置

L.data[p] = e; //将e放入插入位置p上

++(L.length); //表内元素多了一个,因此表长自增1

return 1; //插入成功 返回1

}

说明:

在插入算法实现思路的思考中,有一个点需要注意,按人类的习惯,喜欢见缝插针,所以一般新手同学

在对一个顺序表实现插入算法的时候,往往把元素之间的位置作为插入位置,这是不好的。

因为顺序表元素之间的位置在相关的程序余元中没有明确的描述方法,因此我们要直接一表中元素所在位置作为插入位置,

假设位置为 i ( i 是某元素在以数组为存储结构的顺序表下标),并统一规定插入元素之间把 i 位置上的元素往后移位。

例如:顺序表{ 3(0)、 1 (1)、 2(2)、5(3)},圆括号为元素的数组下标,思考的时候直接向我可能要插入元素的位置为0 1 2 3

而不要想我要在 0 和 1 之间插入,或者其他连个下标之间插入。

2-2:删除顺序表L中下标p(0<=p<=length-1)的元素 ,成功返回 1,否则就返回 0,并将被删除的元素赋值给 e 。

分析:要删除表中下标为 p 的元素,只需要将其后边元素往前覆盖就可以了,这一就可以达到删除的目的。只需将插入中的元素右移改成左移即可。插入操作中右移的时候需要从最右边的元素开始移动,这里很自然想到在删除操作中左移的时候需要从最左边的元素开始移动。

代码:

int delElem(Sqlist& L, int p, int& e)//需要改变的变量e,所以用引用型

{

int i;

if (p<0 || p>L.length - 1)

return 0; //插入位置不对,返回0,代表删除不成功

e = L.data[p]; //将被删除的元素赋值给e

for (i = p; i <= L.length - 1; ++i) //从p位置开始,开始往前覆盖,实现删除功能

L.data[i] = L.data[i + 1];

--(L.length); //表长-1

return 1; //若删除成功 返回 1

}

说明:通过以上两个例题,可以总结出顺序表的 查找 插入 删除 三种操作。这是考研的重点 必须掌握

顺序表种有两个比较简单的算法在这里做一下介绍

1.初始化顺序表的算法

只需要将 length 设置为 0,代码如下:

void initList(Sqlist& L)//L本身要发生改变,所以用引用型

{

L.length = 0;

}

2.求指定位置元素的算法

用e返回L中的 p(0<=p<=length-1)

int getElem(Sqlist L, int p, int& e)//L不做改变了,但e要改变 所以用引用型

{

if (p<0 || p>L.length - 1) //p值越界错误,返回结果 0

return 0;

e = L.data[p];

return 1;

}

2-2-3单链表的操作

说明:如果没有特殊说明,则链表都是含有头结点的

2-3 A和B是两个单链表(带表头节点),其中元素递增有序。设计一个算法,

将A和B归并成一个按元素值非递减有序的链表C,C由A和B中的结点组成。

分析:一致A,B中元素递增有序,要使归并后的C中元素依然有序,可以从A,B中跳出最小的元素

插入C的尾部,这样使得当A,B中所有的元素都插入C中时,C一定是递增有序的。

分析:很明显,由于A, B是递增的,音痴A中的最小元素是其开始节点中的元素,

所以B也一样。只需要从A,B的开始节点中选出一个较小的来插入C的尾部即可

注意:A与B中的元素有可能一个也已经全部被插入C中了,另一个还灭有查完,如果A中所有元素已经插入完毕,而B还未插入完毕,

这说明B中所有的元素均大于C元素,这里秩序将B链接到C的尾部即可。A若没有查完,也是如此操作

void merge(LNode* A, LNode* B, LNode*& C)//  *:表示引用,并没有修改   &:表示取地址,修改内存空间保存的数据了

{

LNode* p = A->next; //p去跟踪A的最小结点

LNode* q = B->next; //q去跟踪B的最小结点

LNode* r; //r始终指向C的终端结点

C = A; //用A的头结点来做C的头结点

C->next = NULL; //看下面的答疑

free(B); //B的头结点已经无用,释放头结点

r = C; //r指向C,因为此时的头结点也是终端节点

while (p != NULL && q! = NULL) //当p与q不为空的时候,选取p和q所只结点的较小者,插入

{

/*以下的if else语句中,r始终只想当前链表的终端结点,作为接纳一个新结点的媒介,通过他

 通过它,新结点被链接入C并且重新的终端结点,以便于接收下一个新结点,这里体现了建立链表

   的尾插法思想。*/

if (p->data <= q->data)  //A大!!!选他

{

r->next = p;

p = p->next;

r = r->next;

}

else           //B大!!!选他

{

r->next = q;

q = q->next;

r = r->next;

}

}

r->next = NULL;  //看下面的答疑

/*以下两个if语句将还有剩余结点的链表链接在C的尾部*/

if (p != NULL) r->next = p;

if (q != NULL) r->next = q;

}

由注释 个人理解 可以看看

答疑!!!!!

1)C->next=NULL与r->next=NULL;是不是表示到目前(这两句代码结束的地方)为止C链表已经构造完成?

2)为什么LNode *p=A->next这行代码可以表示p来跟踪A的最小值结点?A->next 不是表示A的去下一个分量的意思吗?

3)为什么代码只用了id语句就可以把剩余结点接入C的尾部,如果哟u多个剩余结点,岂不是应该用一个循环来将所有结点逐一接入?

回答!!!!!

1)C->next=NULL;在这个程序中表示从A链表中取下头结点作为新链表的头,r->next=NULL 这一句其实是可以去掉的,因为下边两个if语句必须存在一个要执行.

2)A->next 表示A链表的开始结点(头结点后边的那一个)A链表是递增的,用P指向它,即p指向A的最小结点,即p是用来跟踪A的最小结点

3)类比一下现实生活中的接链子,是仅需要接上掉的一环,还是需要把所有的环都给断掉重新接一遍

例2-3中涵盖了两个知识点

尾插法建立单链表

假设有n个元素已经存储在数组a中了,用尾插法建立链表C

void createlistR(LNode*& C, int a[], int n) //要改变的变量用引用型

{

LNode* s,* r; //s用来指向新申请的结点,r始终指向C的终端结点

int i;

C = (LNode*)malloc(sizeof(LNode)); //申请C的头结点空间

c->next = NULL;

r = C; //r指向头结点,因此此时头结点就是终端结点

for (i = 0; i <= n; ++i) //循环申请n个结点来接收数组a中的元素

{

s = (LNode*)malloc(sizeof(LNode)); //s指向新申请的结点

s->data = a[i]; //用申请的结点来接收a中的元素

r->next = s; //用r去接纳新的结点

r = r->next; //r指向终端结点,以便于接纳下一个结点

}

r->next = NULL; //数组a中所有的元素都已经装入链表C中,c的终端结点的指针域为NULL

}

与尾插法相对应的是头插法代码如下

void createlistF(LNode*& C, int a[], int n) //要改变的变量用引用型

{

LNode* s;

int i;

C = (LNode*)malloc(sizeof(LNode));

c->next = NULL;

for (i = 0; i <= n; ++i)

{

s = (LNode*)malloc(sizeof(LNode)); //s指向新申请的结点

s->data = a[i]; //用申请的结点来接收a中的元素

/*下面两句是头插法的关键步骤*/

s->next = C->next; //s所指的新结点的指针域next指向C中的开始结点

C->next = s; //头结点的指针域next指向s结点,使得s称为新的开始结点

}

}

有画图 理解

在上述算法中不断将新结点插入列表的前端,因此新的建立的链表中元素的次序和数组 a 中元素的次序是相反的,加入这里修改一下2-3的题目

单链表的归并操作

2-3-改 :将归并成一个递增的链表哦C改为归并成一个递减的链表哦C,那么如何解决?

只要将插入过程改成头插法就可以解决。这里不需要r追踪C的终端结点,而是用s去接收新的结点,插入链表C的前端

void merge(LNode* A, LNode* B, LNode*& C)

{

LNode* p = A->next;

LNode* q = B->next;

LNode* s;

C = A;

c->next = NULL;

free(b);

while (p != NULL && q != NULL)

{

/*下边的if else语句体现了链表的头插法*/

if (p->data <= q->data)

{

s = p;

p = p->next;

s->next = C->next;

C->next = s;

}

else

{

s = q;

q = q->next;

s->next = C->next;

C->next = s;

}

}

/*下面这两个循环是求和递增归并序列不同的地方,必须将剩余的元素组个插入C的头部才能够得到最终的递减序列*/

while (p != NULL)

{

s = p;

p = p->next;

s->next = C->next;

C->next = s;

}

while (q != NULL)

{

s = q;

q = q->next;

s->next = C->next;

C->next = s;

}

}

有图片解释

上述的头插法的程序中提到了单链表的结点插入操作,此操作很简单,假设p指向一个结点,要将s所致结点插入p所致结点之后的操作如右图

语句为: s->next=p->next; p->next=s;

注意:以上插入操作语句能不能颠倒一下顺序,变为p->next-s; s->next=p->next;呢?

很显然答案是不可以的,因为第一句p->next=s;虽然将s链接在p之后,但是同时也丢失了p直接后续结点的地址(p->next指针原本所存储的p直接后继结点的地址在没有转存到其他地方的情况下被s覆盖,而正确的写法,在覆盖钱就已经将他转存了在s->next中,因而后继结点的地址Iran可以被找到),这样链表断成了两截,没有满足将s插入链表的要求

与插入结点对应的是删除结点,也比较简单

要将单链表的第i个结点删除,必须现在单链表中找到第 i-1 个结点,在删除其后续结点。

例:右图所示,若要删除结点b,则仅需要修改结点a中的指针域。

假设p为指向a的指针,则只需将p的指针域next指向原来p的下一

个结点的下一个结点就可以了

即:p->next=p->next->next;

这里还需要注意,在考试答卷中没删除操作除了修改指针外,还要释放所删除结点的内存空间,即完成的删除操作应该是:

p = q->next;

p->next = p->next->next;

free(p);//调用函数free()来释放q所指向的结点空间

2-4 查找链表C(带头结点)中是否存在一个值的x的结点,若存在,则删除该结点并返回 1 ,否则返回 0.

分析:对于本体需要解决的两个问题:一个是要找到值为x的点,另一个是找到将找到的点删除。

第一个问题引出本章要将的单链表中最后一个重要操作--链表中结点的查找。

为了实现查找,定义一个结点指针变量p,然他沿着链表一致走到表尾,没遇到一个新结点就检测其值是否为

x,是这证明找到,不是就继续检测下一个结点。当找到值为x的结点后就删除该简单。由此可以写出一下代码:

int findAndDelete(LNode *C,int x)

{

LNode *p,*q;

p=C;

/*查找部分开始*/

while(p->next==NULL)

{

if(p->next->data==x)

break;

p=p->next;

}

/*查找部分结束*/

if(p->next==NULL)

return 0;

else

{

/*删除部分开始*/

q=p->next;

p->next=p->next->next;

free(q);

/*删除部分结束*/

return 1;

}

}

说明:

左边程序之所以要是p指向索要删除节点的前驱结点

而不是直接指向索要删除结点本身,是因为要删除一个结

点必须知道其前驱节点的位置,这在之前删除操作的讲解

中已经体现。

目前为止,考研中对于顺序表和单链表算法操作部分所设计的最重要的知识点都已经讲解完毕。考生务必熟悉掌握这些内容。

2-2-4双链表表的操作

(1)采用尾插法建立双链表

void createDlistR(dlnODE *&L,int a[],int n)

{

DLNode *s,*r;

int i;

L=(DLnode *)malloc(sizeof(DLnode));

L->prior=NULL;

L->next=NULL;

r=L; //和单链表一样,r始终指向终端结点,开始的头结点也是终端结点

for(i=0;i<n;++i)

{

s=(DLNode *)malloc(sizeof(DLNode)); //创建新结点

s->data=a[i];

/*下面3句将s插入到L的尾部,并且r指向s,s->prior=r;这一句是建立单链表不同的地方*/

r->next=s;

s->prior=r;

r=s;

}

r->next=NULL;

}

(2)查找结点算法

在双链表中查找第一个值为x的结点,从第一个结点开始,边扫描边比较,

若找到这样的结点,则返回结点指针,否则返回NULL。

DLNode* findNode(DLNoode *C,int x)

{

DLNode *p=C->next;

while(p!=NULL)

{

if(p->data==x)

break;

p=p->next;

}

return p; //如果找到,则p中内容是结点地址(循环break结束);

//如果没找到,则p内容是NULL(循环因p等于NULL而结束)

//因此这一句可以用题干中要求的两种返回值的情况统一起来

}

(3)插入结点的算法

假设在双链表中所指的结点之后插入一个结点s;其操作语句如下:

s->next=p->next;

s->prior=p;

p->next;

s->next->prior=s;//假如p指向最后一个结点,则本行可去掉

说明:

按照图2-16所示的顺序来插入,可以看成一个插入“公式”,其特点是,现将要插入的结点两边链接好,这一就可以保证不会发生链断之后找不到结点的情况。

(4)删除结点的算法

设要删除双链表p结点的后续结点,其操作语句如下:

q=p->next;

p->next=q->next;

q->next->prior=p;

free(q);

2-2-5循环链表的操作

循环单链表和驯化那双链表是由对应的单链表和双链表改造而来,只需在终端结点和头结点间建立联系

即可。循环单链表终端结点的next结点指针指向表头结点;循环双链表终端结点的next指针指向表头结

点,头指针的prior指针指向表位结点。需要注意的是,如果p指针沿着循环链表行走,则判断p走到表尾

结点的条件是p->next==head。循环链表的各种操作均与非循环链表类似

2-2-6逆置问题(408科目重要考点)

问题的提出:给定一个线性表,如何将其中的元素逆置?

可设置两个整型变量 i 和 j,i 指向第一个元素,j 指向最后一个元素,边交换 i 和 j 所指的元素,边让 i 和 j 相向而行

直到相遇,实现代码如下。假设元素存在数组a[]中,left和right是Suunto两端元素的下标。

for (int i=left , j =right; i < j ; ++i ,--j )

{

int temp;

temp= a[ i ];

a[ i ] = a[ j ];

a[ j ] =temp;

}

例题:2-5

(1)将一长度为n的数组的前端k(k<n)个元素你徐厚移动到数组后端,要求元素组中数据不丢失,其余元素的位置无关紧要

分析:只需要逆置真个数组,即可满足前端k个元素逆序后放到数组后端,如图所示

void reverse(int a[],int left,int right,int k)

{

int temp;

for(int i=left; j =right ; i < left + k && i < j ;--j,++i)

{

temp=a[ i ];

a [ i ]=a[ j ];

a [ j ]=temp;

}

}

(2)将一长度为n的数组的前端k(k<n)个元素保持原序移动到数组后端,要求元数组中数据不丢失,其余元素的位置无关紧要

(2)只需要将前端k个元素逆置,然后将整个数组逆置,即可满足前端k个元素保持原序放到数组的后端,如下图所示

(3)将数组中的元素(X0,X1,.... ,Xn-1),经过移动后变为(Xp,Xp+1, ... ,Xn-1,X0,X1, .... ,Xp-1,即循环左移p(0<p<n)个位置)

实现代码如下:

void moveToEnd(int a[], int n,int k)

{

//调用(1)中实现的reverse()函数

reverse(a,0,p-1,p);

reverse(a,p,n-1,n-p);

reverse(a,0,n-1,n);

}

说明:本例第三问为408真题

大纲要求:

1.线性表的定义和基本操作

2.线性表的表现

2.1顺序存储结构

2.2链式存储结构

2.3线性表的应用(这一部分通过线性表算法中的各种题目来讲解,不单独作为一节)

说明:

此处大纲要求,一节本书中所出现的大纲字样,均不特指任意版本的数据结构考研大纲,

这里的大纲是根据多校多年不同版本大纲以及考研真题所总结出来的一个能够适应更多学校考

研要求的大纲

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值