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的移动来处理两节点数据相等的情况。