链表增删改查&循环链表&双向链表&力扣经典链表题分享

链表基本类型,基本操作及例题


  • 创建链表
typedef struct ListNode(){
	int data;
	struct ListNode* next;
}Linklist;

不带头结点:

head=NULL;
  • 带头节点:
  • (注意以下操作都是带头结点哟)
//定义头指针,指针域置空
struct ListNode* head=malloc(sizeof(strcut ListNode));
head->next=NULL;
  • 尾插法
void tail_add(Linklist *head,int n){
    Linklist *p=malloc(sizeof(struct ListNode);
    p->data=n;
    Linklist* t=head;
    t=t->next;
    while(t){
    	t=t->next; //找到最后一个节点
    }
    t->next=p;
    p->next=NULL; //指针域置空
}
  • 头插法

void head_add(Linklist *head,int n){
    Linklist *p=malloc(sizeof(struct ListNode);
    p->data=n;
    p->next=head->next;
    head->next=p; 
}
void add(Linklist *head,int n){
    Linklist *p=malloc(sizeof(struct ListNode);
    Linklist *find=head;
    find=head->next;
    n=n-1;
    while(n--){      //n为增加的节点位置
    	find=find->next;
    }
    int number;
    printf("你要增加的数");
    scanf("%d",&number);
    p->data=number; //原理类似头插法
    p->next=find->next;
    find->next=p; 
}

删,改,查都是类似原理,找到位置,进行改变或输出,以下是伪代码

t=head;
while(n--){
	t=t->next
}
t->next=t->next->next; //指针域指向下一节点的指针域

应用如删除链表中的节点
(题目已给出节点位置,通过值和指针域的覆盖实现交换)

分享力扣删除题:
删除链表的倒数第N个结点
可以用快慢指针,也可以让指针走(总长-n) 步,替换指针域

//快慢指针
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode* dummy=malloc(sizeof(struct ListNode));
    dummy->next=head;
    struct ListNode *fast=head,*slow=dummy;
    while(n--&&fast){
        fast=fast->next;
    }
    while(fast){
        slow=slow->next;
        fast=fast->next;
    }
    slow->next=slow->next->next;
    return dummy->next;
}

//总长-n
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode*dummy=malloc(sizeof(struct ListNode));
    dummy->next=head;
    struct ListNode* t=head;
    int count=0;
    while(t){
        t=t->next;
        count++;
    }
    struct ListNode* start=dummy;
    int i=count-n;
    while(i--){
        start=start->next;
    }
    start->next=start->next->next;
    return dummy->next;
}

删除链表中重复元素
(可能会删除头结点,所以设置哑节点,用x保存相同值,往后若有相同直接删除,返回dummy->next)

  • 改:
t->data=n;
printf("%d",t->val);

循环链表

好处:从表中任一结点出发,均可找到表中其他结点

注意:涉及遍历操作时,由于循环链表中无NULL指针,通过判断是否等于头指针来结束遍历

  • 声明类型
typedef strcut Node{
	int num;
	sttruct Node* next;
}*Linklist
  • 建立:
Linklist create()
{
	Linklist head;
	LNode *p1,*p2;
	char a;
	head=NULL;
	a=getchar();
	while(a!='\n'){
		p1=malloc(sizeof(struct Node));
		p1->num=a;
		if(head==NULL){
			head=p1;
		}
		else{
			p2->next=p1;
		}
		p2=p1;
		a=getchar();
	}
	p2->next=head;
	return head;
}
//主函数
void main(){
	Linklist L1,head;
	L1=create();
	head=L1;
	printf("%d",L1->num);
	L1=L1->next;
	while(L1!=head){
		printf("%c",L->num);
		L=L->next;
	}
	getch();
}
  • 合并两个带尾指针Ta,Tb的循环链表
p=Ta->next; //p保存表头节点
Ta->next=Tb->next->next;
free(Tb->next);
Tb->next=p; 
return Tb;

应用:
环形链表
(判断是否为环形链表 即快指针fast是否会遇上慢指针slow)

双向链表

好处:找前驱节点更加方便

  • 建立
typedef struct ListNode{
	int data;
	struct ListNode*prior,*next;//定义前驱和后继节点
}Linklist

双向链表的对称性:

p->prior->next=p=p->next->prior;
  • 插入
struct ListNode* s=malloc(sizeof(struct ListNode));
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;

  • 删除(需要同时改变前驱和后继的指针域)
p->prior->next=p->next;
p->next->prior=p->prior;

哑节点的应用

应用于头指针可能发生变化,如排序时的调换位置,可能删除删除头结点等,这里给出插入排序,归并排序,冒泡排序,即相关例题

  • 插入排序:

给 small large 分配空间,并分别设置两头结点smallhead,largehead指向这两个链表,

struct ListNode* insertionSortList(struct ListNode* head){
    struct ListNode *dummy=malloc(sizeof(struct ListNode));
    dummy->next=head;
    struct ListNode* lastnode=head,*cur=head->next;
    while(cur){
        if(lastnode->val<=cur->val){
            lastnode=lastnode->next;
        }
        else{
            struct ListNode* prev=dummy;
            while(prev!=cur){
                while(prev&&prev->next&&prev->next->val<=cur->val){
                    prev=prev->next;
                }
                lastnode->next=cur->next;
                cur->next=prev->next;
                prev->next=cur;
            }
            cur=lastnode->next;
        }
    }
    return dummy->next;
}

哑节点属于重新定义类型
另外的,也有重新设置新链表,题如
分隔链表
(设两个链表,分别存放大和小,再置空 相连起来)
奇偶链表

    struct ListNode* odd=head;
    struct ListNode* evenhead=head->next;
    struct ListNode* even=evenhead;

通过改变奇偶节点指针域 且有evenhead偶数链表开端

        odd->next=even->next;
        odd=odd->next;
        even->next=odd->next;
        even=even->next;
  • 冒泡排序
ListNode *slow=head;
ListNode *fast=head->next;
while(fast){
	if(slow->val>fast->val){  //升序
		int temp=slow->val;
		slow->val=fast->val;
		fast->val=temp;
	}
	fast=fast->next;
	slow=slow->next;
}

//治
struct ListNode* merge(struct ListNode* head1, struct ListNode* head2) {
    struct ListNode* dummy=malloc(sizeof(struct ListNode));
    struct ListNode* temp=dummy,*temp1=head1,*temp2=head2;
    while(temp1&&temp2){
        if(temp1->val>temp2->val){
            temp->next=temp2;
            temp2=temp2->next;
        }
        else{
            temp->next=temp1;
            temp1=temp1->next;
        }    
        temp=temp->next;
    }
    if(temp2!=NULL){
        temp->next=temp2;
    }
    if(temp1!=NULL){
        temp->next=temp1;
    }
    return dummy->next;
}

//分
struct ListNode* sort(struct ListNode* head,struct ListNode* tail){
    if(head==NULL){
        return head;
    }
    if(head->next==tail){
        head->next=NULL;
        return head;
    }
    struct ListNode* slow=head,*fast=head;
    while(fast!=tail){
        slow=slow->next;
        fast=fast->next;
        if(fast!=tail){
            fast=fast->next;
        }
    }
    struct ListNode* mid=slow;
    return merge(sort(head,mid),sort(mid,tail));
}


struct ListNode* sortList(struct ListNode* head){
    return sort(head,NULL);
}

链表与递归

力扣 合并两个有序链表


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if (l1==NULL){
        return l2;
    }
    else if (l2==NULL){
        return l1;
    }
    else if(l1->val<=l2->val){
        l1->next=mergeTwoLists(l1->next,l2);
        return l1;
    }
    else{
        l2->next=mergeTwoLists(l1,l2->next);
        return l2;
    }

若有错误,望请指正
如果对你有帮助的话,请点个赞吧~谢谢你

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

blog....

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值