栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

画解数据结构刷题1-3单向链表

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

画解数据结构刷题1-3单向链表

链表旋转

第一题

struct ListNode* rotateRight(struct ListNode* head, int k){
if(k==0||head==NULL||head->next==NULL)
{
    return head;
}
struct ListNode *vtx=head;
int len=1;
while(vtx->next){
vtx=vtx->next;
len++;
}
vtx->next=head;
k=k%len;
int add=len-k;//循环次数
while(add--)
{
    vtx=vtx->next;
}
struct ListNode*ret=vtx->next;
vtx->next=NULL;
return ret;
}

 思路:要输出移动过的链表,先计算len,并让vtx指向最后一个结点,

再将链表首尾相连,再按照题目意思找出适合的循环次数,使vtx遍历到移动后的首元素的前结点,

再输出以前结点的后结点为首元素的链表,将最后一个结点(即前结点)的next断掉,输出

第二题

 

 

 注意:如果按第二个 写,cur之前有联系,但最后输出的是pre,没有链表产生,所以每次要新构建一个strcut为cur->next,让其与pre产生链表(每次while时将cur给p),cur=next就等于原先的cur=cur->nect,但是这里next已经变了

链表相交

 

 

太巧妙了这双指针,简单学习一下链表双指针的写法

链表中的双指针是创建一个新结点,并让vtx=vtx->next,只有两个相等时才输出

链表归并

第一题

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* newlist;
newlist=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode*tail=newlist;//tail指向newlist的头结点,所以返回newlist->next
struct ListNode*p1=list1;//指向两表的头结点
struct ListNode*p2=list2;
while(p1!=NULL&&p2!=NULL)
{
    if(p1->val<=p2->val)
    {
tail->next=p1;
tail=p1;//list1不会被清空
p1=p1->next;
    }
    else{
        tail->next=p2;
        tail=p2;
        p2=p2->next;
    }
}
if(!p1)
       { tail-> next = p2 ; }
    else if(!p2)
        { tail-> next = p1; } 
return newlist->next;
}

思路:创建一个新结点并为其申请空间,初始化指针指向新结点(新链表),所给2链表的头结点,比较两指针大小,并使用尾插法和tail指针插入元素,最后如果还有剩余,就把他都插入新list

1.将l1赋值给cur

2.为cur->next申请空间并把curnext给cur

3.l1=l1->next

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    struct ListNode*newlist=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode*tail=newlist;//指向newlist的头节点
    struct ListNode*head=newlist;
    if(list1==NULL&&list2==NULL)
    {
        return NULL;
    }
    if(list1==NULL&&list2!=NULL)
    {
        return list2;
    }
    if(list1!=NULL&&list2==NULL)
    {
        return list1;
    }
    while(list1&&list2)
    {
        if(list1->valval)
        {
tail->next=list1;
tail=list1;
list1=list1->next;
       }
       else{
tail->next=list2;
tail=list2;
list2=list2->next;
       }
    }
    tail->next=list1?list1:list2;
    return head->next;
}

或者初始化头和尾结点,不断利用尾结点插入元素,最后输出head->next

第二题

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    struct ListNode*newlist=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode*tail=newlist;//指向newlist的头节点
    struct ListNode*head=newlist;
    if(list1==NULL&&list2==NULL)
    {
        return NULL;
    }
    if(list1==NULL&&list2!=NULL)
    {
        return list2;
    }
    if(list1!=NULL&&list2==NULL)
    {
        return list1;
    }
    while(list1&&list2)
    {
        if(list1->val<=list2->val)
        {
tail->next=list1;
tail=list1;
list1=list1->next;
       }
       else{
tail->next=list2;
tail=list2;
list2=list2->next;
       }
    }
    tail->next=list1?list1:list2;
    return head->next;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    for(int i=1;i 

思路:利用将2个升序链表合并的代码,for循环将list[0]与1到n的所有list进行合并

注意:

在2个链表合并的代码中,注意是为一个结点申请空间,然后初始化指针指向他

int FindMin(struct ListNode** List, int listsSize){
    int index=0, min;
    for(int i=0; ival;
            break;
        }
    }
    for(int i=0;ival<=min){
            min = List[i]->val;
            index = i;
        }
    }
    return index;
}

struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    int index;
    if(listsSize==0)
    {
        return NULL;
    }
   struct ListNode*Ar[listsSize];
   struct ListNode*ans=(struct ListNode*)malloc(sizeof(struct ListNode));
   struct ListNode*tail=ans;
   struct ListNode*head=ans;
   for(int i=0;inext=Ar[index];
tail=Ar[index];
Ar[index]=Ar[index]->next;
   }
   return head->next;
}

定义一个在二维数组(存放头结点)中寻找最小值index的函数

{
如果全为null,就要返回0(指向null),循环比较lists[i],更新min和i

}

为一个头结点申请空间,初始化head和tail指针,初始化一个数组ar,存放lists的头结点,

在while(1)里

不断找ar中最小的index,并用尾插法插入,并将使用到的index结点指向其后继结点

第三题

void reorderList(struct ListNode* head){
struct ListNode*cur=head;
struct ListNode*vec[40001];
int i=0;
while(cur)
{
vec[i]=cur;
cur=cur->next;
i++;
}
int p=0;
int q=i-1;
while(pnext=vec[q];
    p++;
    if(p==q)//偶数的时候有用,不然还会执行到下面的语句
    {
        break;
    }
    vec[q]->next=vec[p];
    q--;
}
vec[p]->next=NULL;
}

思路:需要先插第一个,再插最后一个,再插第二个,而单向链表的缺点就是每次查找都要遍历,所以可以将他存入线性表(即数组)中去,每次存只需用vec[1]或vec[n-1]等等

所以,先创建一个数组,将所有结点存入

再定义头尾指针,循环插入,中间的if与奇偶元素不同情况有关

最后将最晚插入的结点的next=NULL

第四题

 

struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2){
struct ListNode*cur=list1;
struct ListNode*head=list1;
struct ListNode*pa;
struct ListNode*pb;
int i=0;//记录下标
while(cur)
{
    if(i==(a-1))
    {
        pa=cur;
    }
    if(i==(b+1))
    {
        pb=cur;
    }
    cur=cur->next;
    i++;
}
pa->next=list2;
struct ListNode*vtx=list2;
while(vtx->next)
{
    vtx=vtx->next;
}
vtx->next=pb;
return head;
}

思路:重点就是拿到list1中a-1和b+1位置的指针(结点),所以先遍历,并设定坐标i,cur每迭代一次就++,就能拿到位置为a-1和b+1的指针,然后将l2插到a-1,l2的末尾插入b+1即可

链表排序

 

bool sort(const struct ListNode **a,const struct ListNode **b){
    struct ListNode *p = *a, *q = *b;
    return p->val > q->val;
}
struct ListNode* sortList(struct ListNode* head){
    if(!head) return head;
struct ListNode*ret[50001];
int i=0;
while(head)
{
    ret[i++]=head;
    head=head->next;
}
qsort(ret,i,sizeof(struct ListNode*),sort);
for(int j=0;jnext=ret[j+1];
}
ret[i-1]->next=NULL;
return ret[0];
}

先将结点都存入数组中,注意存入的时候要用head存,而不是指向他头节点的指针存,

然后用指针数组解引用排序cmp的方法排序,再把他们一一连接起来。

总结:真nm难啊

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/832457.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号