0.PTA得分截图
1.本周学习总结
1.1 总结线性表内容
- 顺序表结构体定义
typedef int ElemType;
typedef struct
{
ElemType data[MaxSize]; //存放顺序表元素
int length ; //存放顺序表的长度
} List;
- 构建顺序表
void CreateList(SqList& L, int n) //构建顺序表函数 ,n为顺序表长度
{
L = new List;
L->length = n;
for (int i = 0; i < n; i++)
{
cin >> L->data[i];
}
}
- 顺序表插入
void InsertSq(SqList& L, int x) //顺序表插入函数,x为要插入的数据
{
int i, j;
if (L->data[0] > x) //要插入的数据比顺序表第一项元素还小
{
for (j = L->length; j > 0; j--)
{
L->data[j] = L->data[j - 1];
}
L->length++;
L->data[0] = x;
}
for (i = 0; i < L->length - 1; i++) //要插入的数据在顺序表第一项元素和最后一项元素之间
{
if (L->data[i] < x && L->data[i + 1] > x)
{
for (j = L->length; j > i+1;j--)
{
L->data[j] = L->data[j - 1];
}
L->length++;
L->data[i + 1] = x;
return;
}
}
if (L->data[L->length - 1] < x) //要插入的数据比顺序表最后一项元素还大
{
L->data[L->length] = x;
L->length++;
return;
}
}
- 顺序表删除
for (i = 0; i < L->length; i++)
{
if (L->data[i] >= min && L->data[i] <= max)
{
for (j = i; j < L->length - 1; j++)
{
L->data[j] = L->data[j + 1];
}
L->length--;
i--; //避免删除一项元素后,此元素的后一项元素会被跳过
}
}
- 链表结构体定义
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next; //指向后继结点
} LNode,*LinkList;
- 头插法建链表
void CreateListF(LinkList& L, int n)
{
LinkList pre;
L = new LNode;
L->next = NULL;
ElemType i;
for ( i = 0; i < n; i++)
{
pre = new LNode;
cin >> pre->data;
pre->next = L->next;
L->next = pre;
}
}
- 尾插法建链表
void CreateListR(LinkList& L, int n)
{
LinkList tail, p;
L = new LNode;
tail = L;
L->next=NULL;
for (int i = 0; i < n; i++)
{
p = new LNode;
cin >> p->data;
p->next = NULL;
tail->next = p;
tail = p;
}
}
- 有序单链表数据插入
void ListInsert(LinkList& L, ElemType e)
{
LinkList ptr, p;
p = L->next;
while (p->next)
{
if (p->data <= e && p->next->data >= e)
{
ptr = new LNode;
ptr->next = NULL;
ptr->data = e;
ptr->next = p->next; //头插法插入数据
p->next = ptr;
return;
}
p = p->next;
}
if (p->data <= e) //数据插入到尾结点后
{
ptr = new LNode;
ptr->next = NULL;
ptr->data = e;
p->next = ptr;
}
- 有序单链表数据删除
void ListDelete(LinkList& L, ElemType e)
{
LinkList ptr, p;
p = L;
int flag = 0;
if (p->next == NULL||p==NULL) //判断空链表
{
return;
}
while (p->next)
{
if (p->next->data == e)
{
ptr = p->next;
p->next = p->next->next;
delete ptr;
flag = 1;
}
p = p->next;
if (p == NULL)
{
break;
}
}
if (flag == 0)
{
cout << e << "找不到!" << endl;
}
}
- 有序链表合并
void MergeList(LinkList& L1, LinkList L2)
{
LinkList ptr = L1,p; //合并的链表头结点为L1的头结点
while (ptr->next && L2->next)
{
if (ptr->next->data > L2->next->data)
{
p = new LNode;
p->data = L2->next->data;
p->next = ptr->next;
ptr->next = p;
L2 = L2->next;
}
else if (ptr->next->data == L2->next->data)
{
L2 = L2->next;
}
ptr=ptr->next;
}
if (ptr->next == NULL )
{
ptr->next = L2->next;
}
}
- 循环链表
- 定义:循环链表中最后一个结点的指针域指向头结点,整个链表形成一个环 。判断循环链表为空链表的条件是:头指针L->next==L。
- 循环单链表图片:
- 双链表
- 定义:双向链表也叫双链表,其每个数据结点都有两个指针,分别指向直接前驱结点和直接后继结点。从双链表中的任意一个结点开始,都可以访问其前驱结点和后继结点。
- 双链表图片:
1.2 对线性表的认识及学习体会:
- 自我感觉线性表中顺序表比链表更简单,因为里面有很多数组的知识,至于链表方面一定要弄清楚节点间的关系,单链表中尤其注意指针next的用法。先把基础打牢,如先学会尾插法,头插法建链表,再循序渐进,如学会有序链表的插入,删除,合并等。我最开始做题时就常常出现指针为空指针,非法访问地址,尾节点数据重复输出等问题。
2.PTA实验作业
2.1 题目1:7-1 两个有序序列的中位数
2.1.1代码截图
2.1.2本题PTA提交列表说明
- 部分正确(6):新建顺序表L3时直接用赋值表达式,没法把顺序表L1的每项元素赋给L3。解决办法:运用一个循环,分别把顺序表L1的每项元素赋给顺序表L3。
- 部分正确(17):-->用C语言知识构造数组时,对数组L3中的元素排序时这种情况有问题。解决办法:每次在选择排序时内层循环之前都把变量i的值赋给变量k。
- 编译错误:-->定义变量时大小写错误
- 部分正确(21):
2.2 题目2:6-3 jmu-ds- 顺序表删除重复元素
2.2.1代码截图
2.2.2本题PTA提交列表说明
- 部分正确:-->题目并未说出顺序表长度为零时该输出什么,直接return 回去就行。
2.3 题目3:6-9 jmu-ds-有序链表合并
2.3.1代码截图
2.3.2本题PTA提交列表说明
- 部分正确:-->合并的链表头指针为链表L1的头指针,但在循环中缺少指针移动的语句,即此指针无法指向链表L1的下一节点。
3.阅读代码
3.1 21. 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
- 解题代码:
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if (l1 == NULL) return l2;
if (l2 == NULL) return l1;
struct ListNode *l3,*head ;
head = (struct ListNode*)malloc(sizeof(struct ListNode));
l3 = head;
while(l1&&l2)
{
if (l1 -> val < l2 -> val)
{
l3 -> next =l1;
l1 = l1 -> next;
l3 = l3 -> next;
}
else
{
l3 -> next = l2;
l2 = l2 -> next;
l3 = l3 -> next;
}
}
l3 -> next = l1 ? l1 : l2;
return head -> next;
}
3.1.1 该题的设计思路
如果链表l1为空链表,合并的链表就为l2,返回链表l2。反之亦然。
两链表l1,l2的长度都为n,算法的时间复杂度T(n)=O(n),算法的空间复杂度S(n)=O(1)
3.1.2 该题的伪代码
定义新链表l3的头指针head
while(l1&&l2)
{
if(链表l1节点的数据更小)
{
l1节点作为l3的后继节点
l1,l3同时移动到下一节点
}
else
{
l2节点作为l3的后继节点
l2,l3同时移动到下一节点
}
}
end while
把l1,l2两条链表中未走完的那条接到链表l3的后面
返回头指针head
3.1.3 运行结果
这段代码中最后应为return head,即返回头指针,不然最后输出时会少掉头节点中的元素。修改代码后运行如下:
3.1.4 该解法解题优势及难点
- 该解法构建了一条新的链表,在不断移动两条链表l1和l2的过程中对比节点数据的大小,并把具有较小数据的节点作为新链l3的后继节点,若一条链先结束,则将另一条链的其余节点接到新链的后面,最后返回新链l3的头指针。但要注意返回的应是头指针,而不是头节点。且在链表l1,l2移动之前应先把新链l3的头指针赋给一个指针变量,接下来让此变量代替头指针head移动。
3.2 83. 删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
- 解题代码
ListNode* deleteDuplicates(ListNode* head)
{
if(!head)
return head;
ListNode*first = head,*second = first->next;
while(first&&second)
{
if(first->val!=second->val)
{
first->next=second;
first=second;
}
second=second->next;
}
first->next=second;
return head;
}
3.2.1 该题的设计思路
链表长度为n,算法的时间复杂度T(n)=O(n),空间复杂度S(n)=O(1)
3.2.2 该题的伪代码
判断链表是否为空
while(头节点first和下一节点second)
{
若两节点数据不同,移动头节点first
移动节点second
}
end while
链表尾部置空,返回头节点
3.2.3 运行结果
3.2.4 该解法解题优势及难点
- 该解法把头节点head赋给了指针变量first,并用指针变量second表示链表的下一节点,之后便不断移动指针second,并分别把相应节点的数据与指针first对应节点的数据进行对比,若不等,则把指针second对应的节点作为指针first对应节点的后继节点。最后把链表尾部置空并返回头节点,此解法在循环过程中通过指针second的移动来处理两节点数据相等的情况。