数据结构算法题个人笔记——链表篇

前言

注意:在使用下列代码时,若无特别说明,链表都是带头结点的。

typedef struct LNode{
	int val;
	struct LNode *next;
}LNode;

题目一:使用头插法创建链表

/*
arr:链表数据
head:头指针
*/
LNode* createListByHead(int arr[], LNode *head, int len){
	int i;													//p为工作指针
	LNode *p = NULL;										//工作指针
	head->next = NULL;										//将头结点中的next指针置为空
	for(i=0; i<len; ++i){	
		//创建结点并设置数值域
		p = (LNode*)malloc(sizeof(LNode));					//为新结点开辟空间,并将工作指针p指向它
		p->val = arr[i];
		//头插
		p->next = head->next;															
		head->next = p;							
	}
	return head;
}

题目二:使用尾插法创建链表

/*
arr:链表数据
head:头指针
*/
LNode* createListByTail(int arr[], LNode *head, int len){
	int i;
	LNode *p = NULL, *r = head;								//p为工作指针;r为链表的尾指针,起始位置指向头结点
	for(i=0; i<len; ++i){
		//创建结点并设置数据域
		p = (LNode*)malloc(sizeof(LNode));					//为新结点开辟空间,并将工作指针p指向它
		p->val = arr[i];
		p->next = NULL;										//记得将新节点中的next指针置为空
		//尾插
		r->next = p;										
		r = p;
	}
	return head;
}

题目三:反转链表

/*
head:头指针
思想:
步骤一:将表的头结点与其后续断开
步骤二:遍历后序部分,依次向前序部分头插
*/
LNode* reverseList(LNode *head){
	LNode *p, *s;										//s指向p的后继结点,两者起始位置相同
	p = s = head->next;
	head->next = NULL;									//将表头与后序断开
	while(p){
		s = p->next;									//s指向p指向结点的后继,否则一会找不到下一个头插的结点
		//当前结点头插到前序部分
		p->next = head->next;
		head->next = p;
		//p指向即将进行头插的结点
		p = s;											
	}
	return head;
}

题目四:删除链表所有值为指定值的结点

/*
head:头指针
x:指定值
*/
LNode* deleteListByValue(LNode *head, int x){
	LNode *p, *pPre;												
	p = head->next, pPre = head;							//p为工作指针,从第一个结点开始,pPre指向工作指针所指向结点的前驱
	while(p){
		if(p->val == x){
			pPre->next = p->next;							//删除该结点
			free(p);										//释放结点所占空间
			p = pPre->next;
			continue;						
		}
		p = p->next;								
		pPre = pPre->next;
	}
	return head;
}

题目五:合并两个有序链表

/*
l1:链表1
l2:链表2
注意:该题l1,l2无头结点,返回的l3也不带头结点
感兴趣的可以自己在LeetCode上实现一下:https://leetcode-cn.com/problems/merge-two-sorted-lists/
*/
LNode* mergeTwoLists(LNode* l1, LNode* l2){
    LNode *l3 = (LNode*)malloc(sizeof(LNode));
    LNode *p = l3;                 //p为工作指针
    if(!l1) return l2;
    if(!l2) return l1;
    
    while(l1 && l2){
        if(l1->val < l2->val){
            p->next = l1;
            l1 = l1->next;
        }else{
            p->next = l2;
            l2 = l2->next;
        }
        p = p->next;
    }
    if(!l1) p->next = l2;
    if(!l2) p->next = l1;
    return l3->next; 
}

题目五:使用选择排序对链表排序

/*
!无头结点
head:指向第一个结点
*/
struct ListNode* sortList(struct ListNode* head){
    struct ListNode *p = head, *q, *minp;
    int temp;
    while(p){
        minp = p;
        q = p->next;
        while(q){
            if(minp->val > q->val){
                minp = q;
            }
            q = q->next;
        }
        //交换值
        if(minp != p){
            temp = minp->val;
            minp->val = p->val;
            p->val = temp;
        }
        p = p->next;
    }
    return head;
}

题目六:求链表中倒数第K个结点的值

/*
思想:
①首先定义指针p指向头结点,q也指向头结点
②q向前移动k次
③然后p、q同时移动,最终当q指向最后一个结点时,p指向倒数第K个结点
*/

题目七:判断链表是否为回文链表

/*
思想:
①首先定义一个slow指针和一个fast指针
②从起点开始,slow每次向后移动一次,fast每次向后移动两次,直到fast指向NULL结束{
	当链表长度为偶数时,slow正好指向右半部分的第一个结点
	当链表长度为奇数时:slow正好指向中间结点,其左边一侧结点个数等于右边一侧结点个数
}
③将右半部分反转。
④左侧第一个结点与右侧第一个结点比较,两者依次向后比较。	
*/

题目八:求两链表的公共结点

在这里插入图片描述

/*
思路:若两个链表有一个公共结点,则该公共结点到两链表尾部每个都是依次重合的。
*/
struct ListNode* searchCommon(struct ListNode* l1, struct ListNode*l2){
	int len1=Length(l1), len2=Length(l2);
	int i,diffLen;
	//比较长度并移动指针
	if(len1 > len2){
		diffLen=len1-len2;
		for(i=0; i<diffLen; i++){
			l1=l1->next;
		}
	}else{
		diffLen=len2-len1;
		for(i=0; i<diffLen; i++){
			l2=l2->next;
		}
	}
	//从该位置依次往后比较
	while(l1 && l2){
		if(l1==l2) return l1;				//两个结点及其它后继结点全部相同l1==l2才成立
		else{
			l1=l1->next;
			l2=l2->next;
		}
	}
	return NULL;
}

题目八:设计算法判断带头结点的循环双链表是否对称

boolen simiar(ListNode* L){
	ListNode *p=L->next,*q=L->poior;			//首位工作指针
	while(p!=q && q->next!=p){					//循环直接条件,!是q->next
		if(p->data==q->data){
			p=p->next;
			q=q->poior;
		}else return 0;
	}
	return 1;
}

题目九:判断链表中是否有环

思路:快慢指针,一个一次向后移动一次,另一个一次向后移动两次。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值