南航829数据结构

该篇博客探讨了多种链表操作的算法思想,包括取两个递增链表的交集并返回递减链表、奇数序号结点倒序、删除不排序链表的重复结点、合并递减链表等。每种操作都详细阐述了时间复杂度和空间复杂度,并提供了相应的代码实现。

DS代码 仅仅作为一个记录

链表

真题
2013
算法思想

p,q分别指向A,B。若p -> data > q -> data q指针后移,p -> data < q -> data p指针后移并且删除原p结点,p -> data = q -> data,p结点尾插法插入到A后面,实现倒序,并且后移pq指针,直到遍历完其中一个链表,最后删除A中后面多余的结点,返回头节点A。

  • 时间复杂度:O(N+M),对链表每个节点遍历了一次;
  • 空间复杂度:O(1),只使用了常量的空间。
原题版本
// 取两个递增链表的交集,返回递减链表
// 如果有重复元素可以设置一个int型变量记录两次插入的结点数值是否相同

LinkList GetCommon(LinkList A, LinkList B){
    LNode *p = A -> next, *q = B -> next, s = NULL;
    A -> next = NULL; //清空链表

    while(p && q){// data比较,判断是否为交集中的元素,偏小则后移
        if(p -> data < q -> data){
            s = p -> next; //删除A中不是交集中的结点
            free(p);
            p = s; 
        }

        else if(p -> data < q -> data){
            q = q -> next //返回A,不对B处理 
        }

        else{
            s = p -> next; //头插法插到A后面,倒序
            p -> next = A -> next;
            A -> next = p;
            p = s;
        }

        while(p){
            s = p -> next; //删除A中其他结点
            free(p);
            p = s;
        }
    }
    return A;//带头节点
}
改进版本
// 取两个递增链表的交集,返回递减链表
// 如果有重复元素可以设置一个int型变量记录两次插入的结点数值是否相同

LinkList GetCommon_New(LinkList A, LinkList B){
    LNode *p = A -> next, *q = B -> next, s = NULL;
    A -> next = NULL; //断开链表用于插入
	int oldn = -1, newn = -1while(p && q){// 判断是否为交集中的元素
        if(p -> data < q -> data || p -> data == oldn){ //与上次加入的结点重复时也删除
            s = p -> next; //删除A中不是交集中的结点
            free(p);
            p = s; 
        }

        else if(p -> data < q -> data){
            q = q -> next //返回A不对B处理 
        }

        else{
            oldn = p -> data;
            s = p -> next; //头插法插到A后面倒序
            p -> next = A -> next;
            A -> next = p;
            p = s;
        }

        while(p){
            s = p -> next; //删除A中其他结点
            free(p);
            p = s;
        }
    }
    return A;//带头节点
}
2014
算法思想

自己先想到的:首先遍历链表得到最后一个奇编号结点p,然后遍历链表利用pq指针将偶数序号结点头插法插入到p结点之后,直到被删除结点的前驱节点指向p时(原链表已完成操作)结束返回L, 若非结点数小于3无需操作直接返回

狮子的:不同点,把偶数结点尾插到新申请结点B的后面,操作完成后拼接AB链表

  • 时间复杂度o(n):进行一次or两次遍历链表

  • 空间复杂度:O(1):只使用了常量的空间。

实现代码自己的
//奇数序号结点倒序尾插到偶数结点之后

LinkList DoubleReverse(LinkList L){
    LNode *p = L -> next, *q = L, *s = NULL, *last;

    while(p -> next -> next){ //找到最后一个奇数结点
        p = p -> next -> next;
    }
    last = p;

    while(q -> next -> next){ //判断未遍历结点数量
        s = q -> next; //把偶数结点移出链表
        
        if(s != last){ //判断是否完成插入
            q = s -> next;
       	 	s -> next = q -> next;

        	q -> next = p -> next; //头插法加入到链表的尾部
        	p -> next = q;
        	p = q;
            q = s -> next;
        }
        else{
            break;
        }
    }

    return L;
}
狮子的
LinkList fun(LinkList A){
	LinkList p = A->next;
	if(!p->next){return A;}
	LinkList q = p->next; /* p 指向 A 的第一个结点 */
	LinkList B= (LinkList) malloc(sizeof(LNode) );
	B->next = NULL; /* 创建链表 B */
	while (p&&q)
	{
		p->next = q->next;
		q->next = B->next;
		B->next = q;
		if(p->next){
			p=p->next;
			q=p->next;
		}else{break;}
	}
	p->next = B->next; /* A 后接 B */
	free(B);
    reruen A;
}
2015
算法思想

使用p指针遍历链表,用max指针指向本次遍历data最大的结点,遍历完成后将此结点头插法到B后面,多次重复步骤直到L的next为空,返回B即为从小到大排序的链表。

  • 时间复杂度o(n2)o(n^2)o(n2)空间复杂度o(1)
实现代码
// 链表简单快速排序从小到大

LinkList ListSort(LinkList L){
    LinkList B = (LinkList)malloc(sizeof(LinkList));
    B -> next = NULL;

    LNode *pre = L, *p = L -> next;
    LNode *max = L -> next, *maxpre = L;

    while(L -> next){
        pre = L, p = L -> next;
        max = L, maxpre = L -> next;

        while(p){
            if(p -> data > max -> data){
                max = p;
                pre = maxpre;
            }

            p = p -> next;
            pre = pre -> next;
        }

        maxpre -> next = max -> next;
        max -> next = B -> next;
        B -> next = max;
    }

    L -> next = B -> next;
    free(B);

    return L; 
}
2016
算法思想

遍历链表同时创建一个新的头节点B,若遍历当前结点和B中结点重复(此时也对B进行一次遍历判断重复,利用int变量n记录是否重复)则删除,不重复则插入到B后面,直到原链表为空。

狮子的:遍历到当前结点时,对之前每一个结点进行遍历,如果出现重复则删除当前结点,跳出循环开始遍历下一个结点(狮子代码里面没有跳出,遍历了全部),直到遍历结束,非头节点的节点数小于2时直接返回头节点。

时间复杂度o(n^2)

空间复杂度o(1)

实现代码
// 删除不排序链表的重复结点,重复只保留一个

LinkList DelReElem(LinkList A){
    LNode *q = A -> next;
    LinkList B = (LinkList)malloc(sizeof(LinkList));
    LNode *s = B;
    int n = 1; //记录是否为重复结点
    B -> next = NULL;

    while(A -> next){// 对链表结点依次遍历
        s = B;
        while(s){
            s = s -> next;
            if(q -> data == s -> data){// 重复结点删除
                A -> next = q -> next;
                q = q -> next;
                n = 0
                continue;
            }
        }

        if(n == 1){ // 不重复结点插入到B后
            A -> next = q -> next;
            q -> next = B -> next;
            B -> next = q;
            q = A -> next;
        }
    }

    A -> next = B -> next;// 拼接到原头指针,返回A
    free(B);
    return A;
}
狮子的
void del(LinkList L)
{
	LinkList p=L->next,q=NULL,pre=NULL;
	if(!p){return;} 
	while(p){
		//对于每个节点p,都要将链表里的每个节点遍历一遍确保无重复 
		pre=p;q=p->next;//pre保存q的前驱 
		while(q)
		{
			if(p->data==q->data)
			{	//摘下q,free掉 
				pre->next=q->next;
				free(q);
				q=pre->next;
			}
			else{
				pre=pre->next;
				q=q->next;
			}
		}
		p=p->next;
	}
}
2017
算法思想

狮子申请了一个结点,好像不太好 头插方便逆置(思想如图)

时间复杂度on,空间复杂度o1 别忘记写时间和空间复杂度

实现代码

题目:两个递减链表合并为一个递增的链表,使用原结点操作
在这里插入图片描述

狮子的
LinkList Merge(LinkList A,LinkList B)
{
	LinkList p=A->next,q=B->next,s=NULL;
	LinkList C=(LinkList)malloc(sizeof(LNode));
	C->next=NULL;
	while(p&&q){
		if(p->data==q->data)
		{
			s=p;
			p=p->next;
			s->next=C->next;
			C->next=s;
			s=q;
			q=q->next;
			free(s);
		}
		else{
		 if(p->data>q->data)
			{
				s=p;p=p->next;
			}
		else{
				s=q;q=q->next;
			}
			s->next=C->next;
			C->next=s;
		} 
	}
	while(p){
		s=p;p=p->next;
		s->next=C->next;
		C->next=s;
	}
	while(q){
		s=q;q=q->next;
		s->next=C->next;
		C->next=s;
	}
	return C;
}
2018
算法思想
实现代码

2019
算法思想
实现代码

2020
算法思想
实现代码

2021
算法思想
实现代码

2022
算法思想
实现代码

基础代码
链表倒序
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pre =	 nullptr, *p = head ,*q;

        while(p){
            q = p -> next;
            p -> next = pre;
            pre = p;
            p = q;
        }
        return pre;
    }
};

##二叉树

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值