作者:相国大人
联系:sunxiangguodut@qq.com
版权所有,禁止转载
表栈队列一 正常授课内容 表50 1 线性表52 顺序表的算法103 单链表的算法304 双链表的算法55 循环链表 栈20 1 栈的基本概念2 顺序栈3 链栈4 习题测试 队列15 1 队列基本术语2 顺序队列3 链式队列4 习题测试 数组和矩阵15 1 数组和矩阵2 习题测试 数据结构总复习40注意:线性表是一种逻辑结构,它对应的存储结构是顺序表和链表。
当一个线性表的元素有序时候,称为有序线性表,简称为有序表,有序表是逻辑结构
其中,链表又分为单链表/双链表/循环链表/静态链表
单链表
双链表
循环链表
静态链表
略
链表的特点:
存储空间上比顺序表要付出较大的代价,所以顺序表的存储密度更高。(故意说错成所以线性表的存储密度更高)
链表不具有顺序表的随机存取的特点,但在链表中插入或者删除操作时,只需要修改相关节点指针域即可,不需要移动节点。
2-1-4 线性表采用链表存储时,其存放各个元素的单元地址()
A 必须是连续的
B 是不连续的
C 部分连续
D 连续与否均可以
2-1-8 设线性表有n个元素,以下操作中,()在顺序表上实现比在链表上实现效率更高
A 输出第i个元素值
B 交换第1个元素和第2个元素的值
C 顺序输出这n个元素的值
D 输出与给定值x相等的元素在线性表中的序号
2-1-9 对于一个线性表,既要求能够较快地进行插入和删除操作,又要求存储结构能够反应数据元素之间的逻辑关系,则应采用()存储结构
A 顺序
B 链式
C 散列
D 索引
2-1-10 设线性表中有n个元素,以下操作中,()在单链表上实现要比在顺序表上实现效率更高
A 删除指定位置元素的后一个元素
B 在第一个元素的后面插入一个新元素
C 顺序输出前k个元素
D 交换第i个元素和第n-i+1个元素的值
注意:在线性表中,元素 ai 的序号叫做逻辑序号,在顺序表中,该元素存储在 data[i−1] 中, i−1 称为物理序号。C++中数组下标从0开始,而逻辑序号从1开始,两者相差1.
#define MaxSize 50 typedef struct { ElemType data[MaxSize]; int length; }sqlist;按照元素值查找
int locate_elem(sqlist L,ElemType e) { int where=0; while(where<L.length && L.data[where]!=e) where++; if (where>=L.length) return -1; else return where+1; # or return where }按位插入(背)
int insert_where(sqlist &L, ElemType e, int where) { int j; for(j=L.length;j>where;j--) L.data[j]=L.data[j-1]; L.data[where]=e; L.length++; return 1; }按位删除
int delete_where(sqlist &L, int i) { int j; for (j=i;j<L.length-1;j++) L.data[j]=L.data[j+1]; L.length--; return 1 }有序表的归并
void merge(sqlist L1,sqlist L2, sqlist &L3) { int i=0,j=0,k=0; while(i<L1.length && j<L2.length) { if (L1.data[i]<L2.data[j]) { L3.data[k]=L1.data[i]; i++;k++; } else { L3.data[k]=L2.data[j]; i++;k++; } } while (i<L1.length) { L3.data[k]=L1.data[i]; i++;k++; } while(j<L2.length) { L3.data[k]=L2.data[j]; j++;k++; } L3.length=k; }家庭作业:构建一个顺序表类
你之前不是说王道的书都过了一遍了吗?来来,做做下面这道题。
这是一道模板习题。
2-2-13 设将n(n>1)个整数存放到一维数组R中。试设计一个时间和空间两方面尽可能高校的算法,将R中整数序列循环左移p(0
void reverse(sqlist R[], int left, int right) //1 function { int k=left,j=right,temp; while(k<j) { //2 code block temp=R[k]; R[k]=R[j]; //3 code line R[j]=temp; // k++; j--; } } void shift_left(sqlist R[],int n,int p) { if (p<=0 || p>=n) return 0; reverse(R,0,n-1); reverse(R,0,n-p-1); reverse(R,n-p,n-1); return 1; }算法的时间复杂度为 O(n) ,空间复杂度为 O(1)
2-2-25 用顺序表A和B表示的两个线性表,元素的个数分别为m和n个,若表中数据都是递增有序的,且这m+n个数据中没有重复的。
(1)设计一个算法将这两个顺序表归并到一个顺序表C中,C中元素仍是递增有序的。
(2)如果顺序表B的大小为m+n个单元,是否不利用顺序表C而将合并成的线性表存放在顺序表B中?
(3)设顺序表A前m个元素递增有序,后n个元素递增有序,设计一个算法,使得整个顺序表有序,要求空间复杂度为 O(1) 。
(4)对于(3)若空间复杂度没有限制,能否设计出时间复杂度为 O(m+n) 的算法。
注意:如若没有特别说明,单链表都是带头节点的单链表
头插法与尾插法
void creat_list_front(linklist *&head, ElemType a[],int n) { linklist *s;int i; #head = (linklist *)malloc(sizeof(linklist)); linklist* head=new(linklist); head->next =NULL; for (i = 0; i<n;i++) { linklist* s=new(linklist); s->data = a[i]; s->next = head->next; head->next = s; } } void creat_list_rear(linklist *&head,ElemType a[], int n) { linklist *s,*r;int i; linklist* head = new(linklist); r=L; for (i =0;i<n;i++) { linklist* s=new(linklist); s->data = a[i]; r->next = s; r=s; } r->next =NULL; }按元素值查找
int find_ele(linklist *L,ElemType e) { linklist *p=L->next; int n=1; while(p!=NULL && p->data!=e) { p=p->next; n++; } if (p==NULL)return -1; else return n; }插入节点
s->next=p->next; p->next=s;思考:可否将这两句话颠倒?
删除节点
p->next=p->next->next;注意:指针在等号左边表示指针,在右边表示地址
单链表算法归纳:
基于建表的算法:这类算法直接或者间接地转换成建表的过程,如果新建表的次序与原来的次序相同,则采用尾插法;如果新建表的次序与原来的次序相反,则采用头插法。基于查找/插入或者删除的算法;这类算法以单链表的基本运算为基础,包含有节点的查找/插入或删除操作。PART ONE 10道小题测试:
2-3-1 带头节点的单链表L为空的判定条件是()
A L=NULL
B L->next==NULL
C L->next==L
D L!=NULL
2-3-5 在单链表中,增加一个头节点的目的是为了()
A 使单链表至少有一个节点
B 标识链表中重要节点的位置
C 方便运算的实现
D 说明单链表是线性表的链式存储结构
2-3-6 在一个具有n个节点的有序单链表中插入一个新节点并仍然保持有序的时间复杂度是()
A O(1)
B O(n)
C O(n2)
D O(nlgn)
2-3-7 将长度为n的单链表链接在长度为m的单链表之后的算法时间复杂度是()
2-3-8 已知一个长度为n的单链表中所有节点是递增有序的,以下叙述中正确的是()
A 插入一个节点使之有序的算法时间复杂度为 O(1)
B 删除一个节点使之有序的算法时间复杂度为 O(1)
C 找最小值节点的算法的时间复杂度为 O(1)
D 以上都不对
2-3-9 在一个长度为n(n>1)的带头节点的单链表h上,另设有尾指针r(指向尾节点),执行()操作与链表长度有关
A 删除单链表中的第一个元素
B 删除单链表中的尾节点
C 在单链表第一个元素前面插入一个新节点
D 在单链表最后一个元素后插入一个新节点
2-3-20 在单链表中,要删除某一指定的节点,必须找到该节点的()节点
2-3-15 单链表中p指向一个非尾节点的节点,pre指向其前驱节点,则将p所指节点与其后继节点交换的过程是:
——————————;
——————————;
——————————;
2-3-16 在一个单链表中,已知每个节点只有一个数据域data和一个指针域next,在p所指节点之前插入一个s所指节点时,可执行一下操作:
(1)s->next=
(2)p->next=s;
(3)t=p->data;
(4)p->data=
(5)s->data=
2-3-17 在一个单链表中,已知每个节点只有一个数据域data和一个指针域next,删除p所指节点时,应执行以下操作:
(1)q=p->next;
(2)p->data=q->data;
(3)p->next=
(4)free(q);
PART TWO 2道大题
2-3-48 两个整数序列 A=(a1,a2,⋯,am) 和 B=(b1,b2,⋯,bn) 已经加入两个单链表中,设计一个算法,判断序列B是否是序列A的子序列。
2-3-47 已知3个单链表A,B,C中的节点均依元素值递增有序排列(可能存在两个以上值相同的节点),设计一个算法对A链表进行如下操作:使操作后的链表A中仅留下3个表中均包含的数据元素的节点,且没有值相同的节点,并释放所有无用节点。
插入节点:
在p之后插入节点s
s->next = p->next; p->next->prior = s; s->prior = p; p->next = s;在单链表节点p之前插入一个新节点时,需要找到p节点的前驱节点。而在双链表中某节点p之前插入一个新节点时,只需要找到p节点即可实施插入操作。
删除节点
删除p节点的后继节点
p->next=q->next; q->next->prior=p;在单链表中删除p节点时,需要找到p节点的前驱节点,而在双链表中删除节点p时,只需要找到p节点即可以实施删除操作。
2-4-1 在一个双链表中,在*p节点之后插入 *q节点的操作是()
A. q->prior=p; p->next=q; p->next->prior=q; q->next=p->next;
B. q->next=p->next; p->next->prior=q; p->next=q; q->prior=p;
C. p->next=q; q->prior=p; q->next=p->next; p->next->prior=q;
D. p->next->prior=q; q->next=p->next; q->prior=p; p->next=1;
2-4-2 在一个双链表中,在*p 节点之前插入 *q节点的操作是()
A. p->prior=q; q->next=p; p->prior->next=q; q->prior=p->prior;
B. q->prior=p_prior; p->prior->next=q; q->next=p; p->prior=q->next;
C. q->next=p; p->next=q; q->prior->next=q; q->next=p;
D. p->prior->next=q; q->next=p; q->prior=p->prior; p->prior=q;
在循环链表中,判断表尾p的条件是p->next==L(L为头节点)
其他操作与之前的链表类似
有n个元素,他们的编号为1~n,顺序的进入一个栈,则可能的出栈序列有()种
以下三类问题等价:
n个不相同的元素进栈的出栈序列个数由n个不相同元素构成不同形态的二叉树个数n个不相同元素的先序序列构成不同形态的二叉树个数3-1-8 已知一个栈的进栈序列是1,2,3,…,n,其输出序列的第一个元素是i(1<=i<=n),则第j(1<=j<=n)个元素是()
A i
B n-i
C j-i+1
D 不确定
15道题,10分钟
15题,10分钟