剑指offer解析(一):线性表,链表相关

本文深入讲解了链表的基本概念及多种实用操作技巧,包括链表的遍历、反转、删除节点、查找公共结点等,并提供了详细的代码示例。
  • 线性表

(1)线性表: 线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。
线性表的逻辑结构简单,便于实现和操作。
(2)基本特征:
1.集合中必存在唯一的一个“第一元素”;
2.集合中必存在唯一的一个 “最后元素” ;
3.除最后一个元素之外,均有 唯一的后继(后件);
4.除第一个元素之外,均有 唯一的前驱(前件)

  • 线性表分类

(1)数组: 存储空间连续

(2)单向链表

(3)双向链表

(4)环形链表

  • 存储结构

链表处理核心:

(1) 链表的节点遍历方式


struct ListNode{
   int val;
   ListNode* next;
};

: 一般在题目中的链表一般以指针的形式给出,所以我们访问的方式是以 ->

链表节点的

(2)链表指针翻转的方法


  • 删除链表中的某个节点

void deleteNode(ListNode* node)
{
    node->val=node->next->val;
    node->next=node->next->next;
    
}

// 删除某个节点的方法,其实就是修改其中的指针即可

  • 链表反转

注意程序的鲁棒性,链表断开等情况

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
         
        if(pHead==NULL) return NULL;//注意程序鲁棒性
         
        ListNode* pNode=pHead;//当前指针
        ListNode* pReverseHead=NULL;//新链表的头指针
        ListNode* pPrev=NULL;//当前指针的前一个结点
         
        while(pNode!=NULL){//当前结点不为空时才执行
            ListNode* pNext=pNode->next;//链断开之前一定要保存断开位置后边的结点
             
            if(pNext==NULL)//当pNext为空时,说明当前结点为尾节点
                pReverseHead=pNode;
  
            pNode->next=pPrev;//指针反转
            pPrev=pNode;
            pNode=pNext;
        }
        return pReverseHead;
    }
};
  • 链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

class Solution {
public:
	ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2)
	{
		ListNode* p1 = pHead1;
		ListNode* p2 = pHead2;

		while (p1 != p2)
		{
			p1 = (p1 == NULL) ? pHead2 : p1->next;
			p2 = (p2 == NULL) ? pHead1 : p2->next;
		}
		return p1;
	}
};
  • 从尾到到头打印链表

(取自剑指offer题)

思路:利用栈的FILO的特性,实现从尾到到头打印链表

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

class Solution {
public:
    void printListFromTailToHead(ListNode* head) {
      stack<ListNode*> sta;
      
      ListNode* pNode=head;
      while(pNode!=NULL)
      {
          sta.push(pNode);
          pNode=pNode->next;
      }
      while(!sta.empty())
      {
          ListNode* ls=sta.top();
          cout<<ls->val<<endl;
          sta.pop();
      }
    }
};
  • 查找链表倒数第k个节点

时间复杂度O(n)

class Solution {
public:
	ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
		if (pListHead == NULL || k == 0) return NULL;
		ListNode* pList_ahead = pListHead;
		ListNode* pList_behind = pListHead;
		for (int i = 1; i < k ; ++i)
		{
			if (pList_ahead->next != NULL)
				pList_ahead = pList_ahead->next;
			else
				return NULL;
		}
		while (pList_ahead->next != NULL)
		{
			pList_behind = pList_behind->next;
			pList_ahead = pList_ahead->next;
		}
		return pList_behind;
	}
};

  • 合并有序链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        ListNode* result = NULL;
        ListNode* current = NULL;
         
        if(pHead1 == NULL)
            return pHead2;
        if(pHead2 == NULL)
            return pHead1;
        while(pHead1 != NULL && pHead2 != NULL){
            if(pHead1->val <= pHead2->val){
                if(result == NULL){
                    current = result = pHead1;
                } else {
                    current->next = pHead1;
                    current = current->next;
                }
                pHead1 = pHead1->next;
            } else {
                if(result == NULL){
                    current = result = pHead2;
                } else {
                    current->next = pHead2;
                    current = current->next;
                }
                pHead2 = pHead2->next;
            }
        }
         
        if(pHead1 == NULL){
            current->next = pHead2;
        }
        if(pHead2 == NULL){
            current->next = pHead1;
        }
         
        return result;
    }
};
  • 删除链表中重复的节点
class Solution {
public:
	ListNode* deleteDuplication(ListNode* pHead)
	{
		if (pHead == NULL) return NULL;
		if (pHead != NULL && pHead->next == NULL) return pHead;

		ListNode* cur;
		if (pHead->next->val == pHead->val) 
		{
			cur = pHead->next->next;
			while (cur != NULL && cur->val == pHead->val)
				cur = cur->next;
			return deleteDuplication(cur);
		}
		else
		{
			cur = pHead->next;
			pHead->next = deleteDuplication(cur);
			return pHead;
		}
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值