• DS博客作业01--线性表


    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的移动来处理两节点数据相等的情况。
  • 相关阅读:
    齐次和线性
    数组指针/指针数组
    坐标转换矩阵
    【转】GMM与K-means聚类效果实战
    利用虚函数实现多态的方式:动态绑定
    类型限定符volatile
    《剑指offer》查找二维数组内元素 c++
    windows下使用命令行编译、链接C++源文件
    关于该博客的美化
    vimium快捷键修改
  • 原文地址:https://www.cnblogs.com/1234hj/p/12407853.html
Copyright © 2020-2023  润新知