链表常见操作

链表常见类型

每一种新数据结构的出现都是为了解决原有数据结构的不足。链表的出现正是为了补充数组只能连续存储的不足。这种离散存储的方式自然携带了动态存储的特性。

单链表

单链表 是链表中最为常见的链表形式,链表中只有一个指向下一结点的指针。链表中的最后一个结点通常指向 NULL,表示链表的结束。

//Definition for singly-linked list.
 struct ListNode {
     int val;
     struct ListNode *next;
 };

单链表有一种特殊形式就是 循环链表,即最后一个结点指向头结点,整个链表形成一个环路

struct ListNode *p1,*p2,*p3;
p1->next = p2;
p2->next = p3;
p3->next = p1;

双向链表

双向链表 与单链表不同的是双向链表中存放了两个指针,pre 指向上一节点, next 指向下一结点。这种链表形式完善了单链表只能向下遍历的缺陷。

//Definition for double-linked list.
 struct ListNode {
     int val;
     struct pre *next;
     struct ListNode *next;
 };
struct ListNode *head,*p,*end; 

head->pre = NULL; head->next = p;
//头结点的上一结点指向 NULL

p->pre = head; p->next = end;
end->pre = p; end->next = NULL;
// 尾结点的下一结点指向 NULL

链表操作

链表的插入

链表的插入大致可分为两种情况,头结点插入和中间结点插入(尾结点插入与中间结点插入操作类似)

头结点插入

思路:让插入结点指向原头结点,指向原头结点的指针指向插入结点

struct ListNode *head,*p;
//设 head 为指向头结点的指针,p 为待插入结点

p->next = head->next;
head = p;
中间结点插入

思路:让插入结点指向插入点的下一结点,指向插入点指向插入结点

struct ListNode *p,*insertNode;
//设 p 为插入结点,insertNode 为待插入结点

insertNode->next = p->next;
p->next= insertNode;

链表的删除

链表的删除可以分为两种情况:

头结点删除:

struct ListNode *head;
//设 head 为指向头结点的指针

head = head->next;
// 头结点已变成下一结点,原头结点从链表中删除

中间结点删除:(尾结点删除与中间结点删除操作类似)

//设 p 为待删除结点,preNode 为待删除结点的上一节点
struct ListNode *p,*pretNode;

// 可以直接 pretNode->next = pretNode->next->next;
pretNode->next = p->next;

有序链表的合并

思路: 合并两个有序链表只需要每次找出当前结点最小值,放入归并链表中。让更小结点链表向下遍历,直至两条链表都遍历完成即完成了两个有序链表的合并

List *mergeTwoLists(List *list1, List *list2)
{
	if (!list1&&!list2) return NULL;
	//当两条链表都为遍历结束则返回 NULL
	
	else if (!list1) return list2;
	//因为都是有序则一条遍历结束后只要将另一条链表接在后面即可
	
	else if (!list2) return list1;
	else if (list1->val<list2->val)
	{
		list1->next = mergeTwoLists(list1->next, list2);
		return list1;
	}
	else
	{
		list2->next = mergeTwoLists(list1, list2->next);
		return list2;
	}
}

单链表翻转

思路: 需要有三个指针,分别指向:上一节点、当前结点、下一结点。

struct ListNode* reverseList(struct ListNode* head) {
	struct ListNode* new_head=NULL,*node=NULL;
	while (head!=NULL)
	{
		new_head = head;//新的头结点等于当前结点
		head = head->next;//当前结点变成下一结点
		new_head->next = node;//当前结点的下一结点为上一结点,从空指针开始
		node = new_head;//上一节点变成当前结点,以此循环,达到链表反转的效果
	}
	return node;
}

单链表的环路检测

思路: 通常用快慢指针来处理类似题目,快指针以慢指针两倍速遍历单链表,若快指针遍历到 NULL 则无环路,若快指针与慢指针指向同一结点,则单链表有环路。

bool hasCycle(struct ListNode *head) {
	struct ListNode *slow,*fast;
    slow=fast=head;
    while(fast&&fast->next&&fast->next->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow==fast)
            return true;
    }
    return false;
}

有序单链表的重复检测

思路: 因为链表是有序的,若下一结点的值与当前结点的值相等则删除该结点

struct ListNode* deleteDuplicates(struct ListNode* head) {
    struct ListNode* p = head;
        while (p&&p->next)
	{
		if (p->val == p->next->val)
            p->next=p->next->next;
		else
		    p=p->next;
	}
    return head;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值