Ch2 作业 | 数据结构

230 阅读3分钟

本章学习要点

  • 熟练掌握线性表在顺序存储结构上实现基本操作的算法
  • 熟练掌握在各种链表结构中实现线性表操作的基本方法,能在实际应用中选用适当的链表结构
  • 能够从时间和空间复杂度的角度综合比较线性表两种存储结构的不同特点及其适用场合

编写链表相关复杂代码的小要点

  • 理解指针和引用的含义
  • 警惕指针丢失和内存泄漏
  • 留意边界条件和特殊情况
  • 举例画图,辅助思考
  • 多写多练,没有捷径

答案:‍‌​⁢‬⁣‍⁢⁡‌​‍⁣⁢⁡⁣⁡‬‬⁢⁣⁢‍⁤​⁡⁤⁣‌⁡⁤‍⁣​⁣⁢‍⁡‍⁣‍‬​⁣2022数据结构-第二章 作业 答案 - 飞书云文档 (feishu.cn)

1. 简答题

  1. 画出执行下列各行语句后最终的各指针及链表的示意图
L = (LinkList)malloc(sizeof(LNode));
p = L;
for(i=1; i<=4; i++){
    P->next = (LinkList)malloc(sizeof(LNode));
    P = P->next; P->data = i*2-1;
}
P->next = NULL;
for(i=4; i>=1; i--)
    Ins_LinkList(L,i+1, i*2);
for(i=1; i<=3; i++) Del_LinkList(L,i);

  1. 已知P结点是某双向链表的中间结点,写出一下操作的语句序列

a. 在P结点后插入S结点的语句序列;

s->prior = p;
s->next = p->next;
p->next->priot = s;
p->next = s;

b. 在P结点前插入S结点的语句序列;

s->next = p;
s->prior = p->prior;
s->prior->next = s;
p->prior = s;

c. 删除P结点的直接后继结点的语句序列;

s = p->next;
p->next = s->next;
s->next->prior = p;
free(s);

d. 删除P结点的直接前驱结点的语句序列;

s = p->prior;
s->prior->next = p;
p->prior = s->prior;
free(s)

e. 删除P结点的语句序列。

s = p->next;
p->prior->next = s;
s->prior = p->prior;
free(p);
  1. 简述以下算法的功能

第1小题

Status A(LinkedList &L){// L是无头结点的单链表
    if(L && L->next){
        Q = L; L = L->next; P = L;
        while(P->next) P = P->next;
        P->next = Q; Q->next = NULL;
    }
    return OK;
}

:把单链表第一个元素移到最后

第2小题

void BB(LNode *s, LNode *q){
    p = s;
    while(p->next !=q) p = p->next;
    p->next = s;
}//BB

void AA(LNode *pa, LNode *pb){
    //pa和pb分别指向不带头结点单循环链表中的两个结点
    BB(pa,pb);
    BB(pb, pa);
}//AA

:将一个单循环链表从 pa 、pb 处分割为两个单循环链表

2. 基础编程练习(本部分自行练习测试,无需提交)

  1. 顺序表的基础操作部分代码git地址为:gitee.com/rainysun/sq…

    1. 按值查找,LocateElem(SqList L, ElemType e)
    2. 删除,ListDelete(SqList &L, int i, ElemType &e)
    3. 划分,Part(SqList &L)
    4. 合并,Merge(SqList A, SqList B, SqList &C)
  2. 链表的基础操作部分代码git地址为:gitee.com/rainysun/li…

    1. 删除第i个元素,ListDelete_L(LinkList L, int i, ElemType &e)
    2. 尾插法建立单链表,CreateList_TL(LinkList &L, int n)
    3. 两个有序单链表合并,Merge(LinkList A, LinkList B, LinkList C)
    4. 单链表逆置,Reverse(LinkList C)

3. 算法设计题(只需要写出函数伪代码)

  1. 算法设计题,从一个给定的顺序表L中删除值在x~y (x<=y)之间的所有元素,要求以较高的效率来实现,写出算法伪代码并分析你的算法时间复杂度。(提示:移动位置一步到位)

void delete(Sqlist &L, int x,int y){
    i=0;
    n=0;
    while(i<L.length){
        if(L.data[i]>=x && L.data[i]<=y){
            n++; //n用来记录当前发现了几个需要删除的数据
        }
        else
            L.data[i-n]=L.data[i] //留下的数据向前移动n个位置
        i++;
    }
    L.length-=n; //修改长度
}
//算法复杂度O(n)

把顺序表中每个元素都访问了一遍,时间复杂度为 O(n)O(n)

  1. 算法设计题,设计一个空间复杂度为O(1)的算法shift(SqList &L, int k)将顺序表L中的元素整体循环左移k位,要求以较高的效率来实现,写出算法伪代码并分析你的算法时间复杂度。

示例数据:顺序表L初始数据为:1,2,3,4,5,6,整体循环左移2位后为:3,4,5,6,1,2

void reverse(SqList &L, int l, int r)
{
	while (l < r) {
		swap(L.elem[l], L.elem[r]);
		l++;
		r--;
	}
}

void Shift(SqList &L, int k)
{
	k %= L.length;
	reverse(L, 0, L.length - 1);
	reverse(L, 0, k - 1);
	reverse(L, k, L.length - 1);
}

只需要做首尾交换的逆序三次即可,时间复杂度为 O(n)O(n)

  1. 算法设计题:设计一个算法删除一个单链表倒数第k个结点

:双指针

void Delet_Link(LinkList &L, int k)
{
	p = L->next;
	while (k--) {
		p = p->next;
	}
	q = L->next;
	while (p->next) {
		p = p->next;
		q = q->next;
	}
	p = q->next;
	q->next = p->next;
	free(q);
}
  1. 算法设计题,设计一个算法检测一个单链表L上是否因为某种错误操作而出现了环。

:快慢指针

bool IsLoop(LinkList L)
{
	p = L;
	q = L->next;
	while (q && q->next) {
		p = p->next;
		q = q->next->next;
		if (p == q) break;
	}
	if (p == q) return true;
	else return false;
}

4. 选做力扣练习题(自己在力扣练习,无需作为作业提交)

  1. (难度:简单)203. 移除链表元素 - 力扣(LeetCode)
  2. (难度:简单)83. 删除排序链表中的重复元素 - 力扣(LeetCode)
  3. (难度:中等)24. 两两交换链表中的节点 - 力扣(LeetCode)
  4. (难度:中等)143. 重排链表 - 力扣(LeetCode)