赞
踩
线性表的定义:线性表是具有相同特性数据元素的一个有限序列。
线性表的逻辑特性
前驱,后继,直接前驱,直接后继
队头(无前驱),队尾(无后继)
线性表的存储结构:顺序存储结构(顺序表)和链式存储结构(链表)
(1)顺序表:
连续存储空间。
随机访问特性。
(2)链表:
逻辑上相邻的两个数据元素其存储的物理位置不要求紧邻。
结点 包含两个域,数据域和指针域,结点的存储空间利用率较顺序表偏低。
不支持随机访问。
支持动态分配。
(1)带头结点的单链表
判断空L->next==NULL
不带头结点时L==NULL
(2)双链表
判断空L->next==NULL
不带头结点时L==NULL
(3)循环单链表
判断空L->next==L
不带头结点时L==NULL
(4)循环双链表
判断空,4选一
1.L->next==L
2.L->prior==L
3.L->next==L&&L->prior==L
4.L->next==L||L->prior==L
(5)静态链表
顺序表和链表的比较总结
(1)基于空间的比较
1)存储分配的方式
顺序表的存储空间是一次性分配的,链表的存储空间是多次分配的
2)存储密度
存储密度=数据本身占用的存储量/结点结构占用的存储量
顺序表100%=数据/总
链表小于100%=(数据+指针)/总
(2)基于时间的比较
1)存取方式
顺序表随机存取,链表顺序存取
2)插入/删除时移动元素的个数
顺序表平均需要移动近一半元素;链表不需要移动元素,只需要修改指针
插入,计算平均移动个数
(1)求概率。如果等概率p=1/n
(2)相应移动个数
平均时间复杂度O(n)
线性表的结构体定义和基本操作
1.顺序表
- #define maxSize 100
-
- // 顺序表
- typedef struct{
- int data[maxSize];
- int length;
- }Sqlist;
-
- // 简单方式
- int A[maxSize];
- int n;
2.单链表
- typedef struct LNode{
- int data;
- struct LNode* next;
- }LNode;
3.双链表
- typedef struct DLNode{
- int data;
- struct DLNode* prior;
- struct DLNode* next;
- }DLNode;
结点的初始化
LNode* A = (LNode*)malloc(sizeof(LNode));
顺序表的操作
- // 查找插入位置
- int findElem(Sqlist L,int x)
- {
- int i;
- for(i=0;i<L.length;++i)
- {
- if(x<L.data[i])return i;
- }
- return i;
- }
- // 插入
- int insertElem(Sqlist &L,int x)
- {
- int pos,i;
- pos = findElem(L,x);
- for(i=L.length-1;i>=pos;++i)
- {
- L.data[i+1] = L.data[i];
- }
- L.data[pos]=x;
- ++(L.length);
- }
- // 删除,返回值成功1 失败0
- int deleteElem(Sqlist &L,int pos,int &e)
- {
- int i;
- if(pos<0||pos>L.length-1)return 0;
- e = L.data[pos];
- for(i=pos;i<L.length-1;++i)
- L.data[i]= L.data[i+1];
- --(L.length);
- return 1;
- }
-
- // 初始化
- void initList(Sqlist &L)
- {
- L.length = 0;
- }
-
- // 获取元素,返回值成功1 失败0
- int getElem(Sqlist L,int pos,int &e)
- {
- if(pos < 0 ||pos >L.length-1)return 0;
- e=L.data[pos];
- return 1;
- }
单链表的操作
插入
删除
双链表的操作
插入
删除
循环链表的操作
对应非循环的方式修改,注意判断是否走到尽头,p->next = L
习题:
1.顺序存储结构优点是_存储密度大_
2.下面关于线性表的叙述中,错误的是(B)
A.线性表采用顺序存储,必须占用一片连续的存储单元
B.线性表采用顺序存储,便于进行插入和删除操作
C.线性表采用链式存储,不必占用一片连续的存储单元
D.线性表采用链式存储,便于进行插入和删除操作
3.线性表是具有n个_数据元素_的有限序列
4.若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除操作运算,则利用(A)存储方式最节省时间
A.顺序表 B.双链表 C.双循环链表 D.单循环链表
5.某线性表最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用(D)存储方式最节省运算时间
A.单链表 B.不带头结点的单循环链表 C.双链表 D.不带头结点且有尾指针的单循环链表
分析:删除O(1),最后插入要找到最后一个,对应查找O(n),解决这个问题O(1)
6.静态链表中指针指示的是_链表中下一个元素在数组中的地址_
7.链表不具有的特点是(B)
A.插入,删除不需要移动元素 B.可随机访问任一元素 C.不必事先估计存储空间 D.所需空间与线性长度成正比
8.将两个有n个元素的有序表归并成一个有序表,其最少比较次数为(A)
A.n B.2n-1 C.2n D.n-1
分析:这里是有序表合并,如果对应长度不一样m和n,则比较最少min{m,n},比完合并,然后剩下的全部并到后面就行
9.单链表L(带头结点)为空的判断条件是(B)
A.L==NULL B.L->next==NULL C. L->next!=NULL D. L!=NULL
10.在一个具有n个结点的有序单链表中插入一个新结点仍然保持有序的时间复杂度是_O(n)_
11.在一个长度为n(n>1)的带头结点的单链表h上,另设有尾指针r(指向尾结点),执行(B)操作与链表的长度有关
A.删除单链表中的第一个结点
B.删除单链表中的最后一个结点
C.在单链表第一个元素前插入一个新结点
D.在单链表最后一个元素后插入一个新结点
分析:L->next,r->next都很方便O(1)。B, ��−1 ,要把r指向它,但它的next要设成NULL,因为不是循环的。要找到它只能从头开始for,时间复杂度O(n)
12.在一个双链表中,在p结点之后插入结点q的操作是
q->next = p->next;
q->next->prior = q;
p->next = q;
q->prior = q;
13.在一个双链表中,在p结点之前插入q结点的操作是
p->prior->next = q;
q->next = p;
q->prior = p->prior;
p->prior =q;
14.在一个双链表中,删除p结点的操作是
p->prior->next = p->next;
p->next->prior = p->prior;
15.非空的单循环链表L(带头结点)的终端结点(由p所指向)满足(D)
A.p->next==NULL B.p==L
C.p->next==L D.p->next==L&&p!=L
分析:空的时候p是指到L的,构成循环p->next==L
16.带头结点的双循环链表L为空的条件是(D)
A.L==NULL B.L->next->prior==NULL C.L->prior==NULL D.L->prior==L&&L->next==L
分析:
17.线性表是_一个有限序列,可以为空_
18.线性表采用链表存储时,其结点地址(D)
A.必须是连续的 B.一定是不连续的 C.部分地址必须是连续的 D.连续与否均可以
19.线性表的静态链表存储结构与顺序存储结构相比,其优点是(C)
A.所有的操作算法实现简单 B.便于随机存取 C.便于插入和删除 D.便于利用零散的存储空间
20.设线性表有n个元素,以下操作中,(A)在顺序表上实现比在链表上实现效率更高
A.输出第i( )个元素值 B.交换第1个元素与第2个元素的值
C.顺序输出这n个元素的值 D.输出与给定x相等的元素在线性表中的序号
21.对于一个线性表,既要求能够快速地进行插入和删除,又要求存储结构能够反映数据元素之间的逻辑关系,则应采用(B)存储结构
A.顺序 B.链式 C.散列(Hash表)
分析:顺序结构要修改位置O(n),链式只要修改指针,散列表缺少逻辑关系的表达
22.需要分配较大的连续空间,插入和删除不需要移动元素的线性表,其存储结构为(B)
A.单链表 B.静态链表 C.顺序表 D.双链表
分析:C是需要移动O(n),链表中连续空间选B
23.如果最常用的操作是取第i个元素的前驱结点,则采用(D)存储方式最节省时间
A.单链表 B.双链表 C.单循环链表 D.顺序表
分析:顺序表随机访问,时间复杂度O(1)。链表是O(n)
24.与单链表相比,双链表的优点之一是(D)
A.插入,删除操作更简单 B.可以进行随机访问 C.可以省略表头指针或表尾指针 D.访问前后相邻结点更灵活
分析:比单链表多出prior指针域,访问前驱更方便
25.在顺序表中插入一个元素的时间复杂度为(C)
26.在顺序表中插入一个元素的时间复杂度为(C)
27.对于一个具有n个元素的线性表,建立其单链表的时间复杂度为(C)
28.若某表最常用的操作是在最后一个结点之后插入一个结点或删除最后一个结点,则采用(D)存储结构最节省运算时间
A.单链表 B.给出表头指针的循环单链表 C.双链表 D.带头结点的循环双链表
29.线性表最常用的操作是在最后一个结点之后插入一个结点或删除第一个结点,则采用(D)存储方式最节省时间
A.单链表 B.仅有头结点的单循环链表 C.双链表 D.仅有尾结点指针的单循环链表
30.设有两个长度为n的单链表(带头结点),结点类型相同,若以h1为头结点指针的链表是非循环的,以h2为头结点指针的链表是循环的,则(B)
A.对于两个链表来说,删除开始结点的操作,其时间复杂度分别为O(1)和O(n)
B.对于两个链表来说,删除终端结点的操作,其时间复杂度都是O(n)
C.循环链表要比非循环链表占用更多的内存空间
D.h1和h2是不同类型的变量
31.若设一个循环表的长度为n。那么,在表中顺序查找一个值为x的元素时,在等概率的情况下,查找成功的数据平均比较次数为_(n+1)/2_。
在向表中第i( )个元素位置插入一个新元素时,为保持插入后表中原有元素的相对次序不变,需要从后向前依次后移_n-i+1_个元素。
在删除表中第i( )个元素时,为保持删除后表中原有元素的相对次序不变,需要从前向后依次前移_n-i_个元素。
综合应用题
(1)线性表可以用顺序表或链表存储,问:
1)如果n个表同时并存,并且在处理过程中各表的长度会动态发生变化,表的总数也可能自动改变,在此情况下,应选用哪种存储表示?为什么?
答:链表。顺序表扩充需要移动大量元素,操作复杂,一般长度第一次分配后固定。链表支持动态改变长度,修改指针域即可完成扩充。
2)若表的总数基本稳定,且很少进行插入和删除,但要求以最快的速度存取表中的元素,这时应采用哪种存储表示?为什么?
答:顺序表。顺序表支持随机访问,时间复杂度为O(1)。顺序表的插入和删除,时间复杂度为O(n)。
对应的链表是顺序访问的,时间复杂度O(n)。但插入和删除修改指针域即可,主要耗时是查找。
(2)为什么在单循环链表中设置尾指针比设置头指针更好?
答:长度为n的单循环链表,在设置尾指针后,只需要进行rear->next就可以访问到第一个元素,rear就可以访问到最后一个元素。但如果是设置头指针,访问第一个front比较方便,但访问最后一个,需要顺序访问所有元素。
(3)设计一个算法,将顺序表中的所有元素逆置
- void swap(int &a, int &b)
- {
- int temp = a;
- a = b;
- b = temp;
- }
- void reverse(Sqlist &L)
- {
- int i,j;
- j = L.length-1;
- for(i=0;i < j; ++i,--j)
- {
- swap(L[i],L[j]);
- }
- }
(4)设计一个算法,从一给定的顺序表L中删除下标i~j( �≤� ,包括i,j)的所有元素,假定i,j都是合法的。
- void deleteRange(Sqlist &L,int i,int j)
- {
- int num,count;
- num = j-i+1;
- for(count=0;count<num;++count)
- {
- L[i+count]=L[j+count+1];
- }
- L.length -=num;
- }
(5)有一个顺序表L,其元素为整型数据,设计一个算法,将L中所有小于表头元素的整数放在前半部分,大于表头元素的整数放在后半部分。
- void setMid(Sqlist &L,int pivot)
- {
- Sqlist M = L;
- int i,j,count;
- i = 0;j=L.length-1;
- for(count = 0; count<L.length-1;count++)
- {
- if(L[count]>pivot)
- {
- M[j] = L[count];
- j--;
- }else{
- M[i] = L[count];
- i++;
- }
- }
- L = M;
- }
(6)有一个递增非空单链表,设计一个算法删除值域重复的结点。例如,{1,1,2,3,3,3,4,4,7,7,7,9,9,9}经过删除后变成{1,2,3,4,7,9}
- void deleteRep(Sqlist &L)
- {
- Sqlist* M = (Sqlist*)(malloc(sizeof(Sqlist)));
- M.append(L[0]);
- M.length=1;
- for(int i = 1;i<L.length;++i)
- {
- if(L[i]>M.getElem(M.length))
- {
- M.append(L[i]);
- M.length++;
- }
- }
- L=M;
- }
精选
1.
- int fact(int n)
- {
- if(n<=1)
- return 1
- return n*fact(n-1)
- }
分析:n(n-1)(n-2)...(2-1)1,执行n次
2.已知两个长度分别为m和n的升序链表,若将他们合并为一个长度为m+n的降序链表,则最坏情况下时间复杂度是(C)
A.O(n) B.O(mxn) C.O(min(m,n)) D.O(max(m,n))
分析:题目表述争议。一般情况,短的比完后O(min(m,n)),剩下的直接塞到后面O(1)
3.下列程序段的时间复杂度是(C)
- count=0;
- for(k=1;k<n;k*=2)
- for(j=0;j<n;j++)
- count++;
乘法法则是组合到一起的,类似分配律。
加法是取大的部分,类似max,常数部分系数C去掉
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。