数据结构习题随笔——线性表
P17 【2010】真
看王道书吧,第一次做错了,费劲艹!
P17 【2011】真
本算法不完美,没注意到两个序列等长。
-
基本思想:
从两个序列的头部开始比较,记录进行比较的次数,每比较一次,次数加1,初始置为 1,比较结果较小的元素向后移位,继续比较;当次数为中位数的位序时,取当前两个较小的数即为中位数。
-
cpp 实现:
#include <iostream> #include <stdlib.h> typedef int ElemType; using namespace std; /********************************************************************* 程序名: FindMid 版权: MHH 作者: MHH 日期: 2021-08-25 11:20 说明: 找出 arr1 和 arr2 的中位数,len1 len2是长度,从序列头依次开始比较,比较次数增加的同时就找到了第 i 大的元素,依照此准则,找到中位数。 *********************************************************************/ ElemType FindMid(ElemType *arr1, ElemType *arr2, int len1, int len2) { int i1 = 0; int i2 = 0; for (int count = 1; count < (len1 + len2) / 2 + 1; count++ ) { if (arr1[i1] < arr2[i2]) { i1++; } else { i2++; } } if (arr1[i1] < arr2[i2]) { return arr1[i1]; } else { return arr2[i2]; } }
-
时间复杂度 O(L + 1) 即 O(n) ,空间复杂度 O(1)
P17【2013】真
建议直接暴力破解,干!
P18【2018】真
寄了,第一次想错了
P18【2020】真
P37 综合应用题 1.
MHH 版本
typedef struct LNode {
ElemType data;
struct LinkList *next;
}LNode, *LinkList;
void DeleteNodesByValue(LinkList &L, ElemType x) {
LNode *p = L;
while (p != NULL && p ->next -> data != x) { // 找到 x 值结点的前驱
LNode *s = p -> next; // s 为删除结点
p -> next = s -> next; // 删除
free(s);
s = NULL;
p = p -> next;
}
if (p == NULL) { // 找不到 x 值,或者 L 为空,或者找到 x 后,已经到了尾部
return;
}else {
DeleteNodesByValue(p -> next, x);
}
}
单链表删除结点需找其前驱对其前驱和该结点操作,或使用“该结点复制后一个结点内容,删除后一个结点”,但在非循环单链表中后者无法删除尾结点
P38 综合应用题 2.
MHH 版本
void DeleteNodesByValue(LinkList &L, ElemType x) {
LNode *p = L;
while (p -> next != NULL) { // 检索整个单链表,p 指向待删除结点的前驱
if (p -> next == x) { // 如果检索到
LNode *s = p -> next; // s 为删除结点
p -> next = s -> next; // 删除 s
free(s);
s = NULL;
}
p = p -> next; // 未检索到便向后移动
}
}
P38 综合应用题 3.
MHH 版本——使用的头插法,不如王道书上的递归简洁
用一个链表完成逆置操作:
- 链表中扫描结点,用 p 指向待前插的结点 s 的前驱。
- 将 p -> next 指向 s -> next。将 p 和 s 的后继链接起来。
- 将s -> next 指向第一个结点 L -> next,L -> next 指向 s,注意此步骤不能反,若反L -> next 已改变,s 无法指向第一个结点了(先处理关系远的 L -> next 和 s)
p 应该指向 待 向第一个结点前插入的结点的前驱
void ReverseList(LinkList &L) {
if (L -> next == NULL)
return; // 空链表,则结束
LNode *p = L; // 指向待操作结点的前驱
while (p ->next != NULL) { // 未到表尾
LNode *s = p -> next; // 将待前插的结点 用 s 指向。
p -> next = s -> next; // 将 p 和 s 的后继链接起来
s -> next = L -> next; // 插入到第一个结点前
L -> next = s;
p = p -> next;
}
p = p -> next; // 逆置完成,重新指向第一个结点
while (p != NULL) {
cout << p -> data;
p = p -> next;
}
}
P38 综合应用题 4.
bool Del_Min(LinkList &L, ElemType &temp) {
if (L -> next == NULL)
return false;
temp = 0; // temp 暂时存储最小值,循环到末尾,它便是最小值了
LNode *p = L; // p 扫描链表,刚开始指向 待删除结点的前驱。 p -> next 指向第 i 个结点
LNode *min_pre = L -> next; // 指向最小值结点的前驱,初始指向第一个结点
while (p -> next != NULL) {
if (p -> next -> data < temp) { // 若当前比暂存最小值还小,则其变成新的最小值,并且记录当前结点指针
temp = p -> data;
min_pre = p; // 指向待删除结点的前驱
}
p = p -> next;
}
LNode *del = min_pre -> next; // del 是待删除结点
min_pre -> next = del -> next;
free(del);
del = NULL;
return true;
}
P38 综合应用题 5.
见数据结构——线性表之逆置。
数据结构习题随笔——树与二叉树
P142 【2017】真
思路:
后序遍历二叉树(用队列存储每一小步,得到的是一个小后缀表达式),初始化一个队列用来增加括号,初始化一个串用来输出,在遍历结点时,有两种情况:
-
数据元素,直接入栈
-
操作符:
如果操作符的指针不等于 Tree 的根结点,则将队列内两个数据元素全部出队,执行 入队“(”、入队第一个数据元素、入队操作符,入队第二个数据元素,入队“)”的操作,然后将队列出队,添加到输出的串上。
如果操作符的指针等于 Tree 的根结点,则直接添加到串后面。
**不如王道书上的简朴!**仔细感悟王道!