【算法】单链表及相关操作

Ref

https://mp.weixin.qq.com/s/hKjkITbCRcnZBafpjiwWJA(理论及java base)

https://blog.csdn.net/qq_29542611/article/details/79265973(单链表实现及算法详细 c实现(包含头结点))

https://blog.csdn.net/zhengnianli/article/details/79320703 (链表详细笔记,增加删除结点算法更好!)

补充:

https://blog.csdn.net/weixin_39916039/article/details/82146763(C++base:反向打印链表:栈(std::stack)和递归(自己套自己,本质是栈)不包含头结点)

c++模板类实现链表:

双向链表:https://blog.csdn.net/zhouzzz000/article/details/80627428

单链表:https://blog.csdn.net/qq_40584417/article/details/80637943

那每个节点结构是由数据域针域组成,数据域是存放数据的,而指针域存放下一结点的地址。

2、头结点:在开始结点之前的结点(可有可无)。其值域不包含任何信息。

3、开始结点:第一个元素所在的结点。

4、头指针:永远指向链表中第一个结点的位置

调整顺序或增减算法实质是 操作next指针:

头插法:(有头结点情况)1.将头结点的next指针赋值给newNode的next指针 2.头结点的next指针再指向newNode

尾插法:1.尾结点的next指针指向newNode 2.newNode的next指针指向nullptr

翻转:(从头上顺序插入元素即可逆转)

https://blog.csdn.net/setsuna_ogiso/article/details/80386982(手撕算法系列,无头结点的翻转)

https://blog.csdn.net/qq_29542611/article/details/79265973(头结点的翻转)

https://blog.csdn.net/weixin_33682719/article/details/93698970(图)

迭代法:

无头结点

//a b c d
ListNode* reverseList(ListNode* phead)
{
	if(phead == nullptr)
	{
		return nullptr;
	}	
	ListNode* pre = nullptr;//此处初始化的值,也就是最后一个node指向的值
	ListNode* cur  = phead;//此处初始化的值为开始结点的值:cur = head(没有头结点)
	ListNode* next = nullptr;
	while(cur!=nullptr)        //第一次肯定进,第二次表示b的右面为null
	{
		next = cur->next; //b后面的保存给c,断开bc,用于步骤3,4的后移操作
		cur->next = pre;//翻转操作:b的next指针指向a
		pre = cur;//pre后移1位
		cur = next; //cur后移1位
	}
//循环完成后,pre就是翻转过来的头,尾为第一次循环时  cur -> next = pre 的pre值(此时cur为最后一个node)
	return pre;
}

ListNode* reverseList(ListNode* list)
{
    ListNode* cur = list;
    ListNode* pre = NULL;
    ListNode* next = NULL;
    while(cur->next != NULL)
    {
        next = cur->next;
        cur->next = pre;
        //此步为下一次循环做的
        //next->next = cur;
        pre = cur;
        cur = next;
    }
    return cur;
}

有头结点

int reverseList(ListNode* phead)
{
	if(phead == nullptr)
	{
		return 0;
	}	
	ListNode* pre = nullptr;
	ListNode* cur  = phead->next;
	ListNode* next = nullptr;
	while(cur!=nullptr)
	{
		next = cur->next;
		cur->next = pre;
		pre = cur;
		cur = next;
	}
    phead -> next = pre;
	return 1;

}

图并不是十分正确,不过概念大概如此

后移: 

看成

注:头结点有无的区别

1.两者在程序上的直接体现就是:头指针只声明

而没有分配存储空间,头结点进行了声明并分配了一个结点的实际物理内存。

2.如果链表有头结点,头指针指向头结点;否则,头指针指向开始结点

3.有无头结点,对于头插法有区别:

   a.有头结点,新插入的结点需要由头结点next指向

   b.无头结点,直接插入第一个,不过头指针改变了!指向新增结点

剑指题解:

1.从尾到头打印链表(运用栈先入后出就行)
2.链表中倒数第k个结点
剑指Offer(十五):反转链表
4.合并两个排序的链表(递归(终结条件:返回非nullptr的一个 递归基:next指向更小的),非递归(while循环将next指向小结点,最后一个为nullptr将另一个放最后))
5.复杂链表的复制(重难点)
这道题有两种思路。第一种普通思路:先顺序复制并且设置好next指针,让新节点的random指向老链表中对应的节点,并且开一个map,一边复制一边存下新旧对应节点地址映射。第二遍遍历根据map把新节点中的random指针都调整正确。这个map消耗了额外空间。
第二种思路:省去这个map,要求是仍然从老节点能直接找到对应的新节点,则方法为把新节点全都缀连在老节点之后。等设置好所有的random之后再拆分两个链表。

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        copyLinkList(pHead);
        setRandom(pHead);
        return splitList(pHead);
    }
private:
  //深拷贝并连接链表,void函数因为会改变已有链表
  void copyLinkList(RandomListNode* pHead)
  {
	RandomListNode* temp = pHead;
	while(temp != nullptr)
	{
		RandomListNode* node = new RandomListNode(-1);
		node->label = temp->label;
		node->next = temp->next;
        node->random = nullptr;//初始值为nullptr
		temp->next = node;//将新结点连接在后面
		temp = node->next;//往后移动
	}
  }
    
    //修改random指针值
    void setRandom(RandomListNode* pHead)
    {
        RandomListNode* node = pHead;
        while(node != nullptr)
        {
            RandomListNode* next = node->next;
            if(node->random != nullptr)
            //if(next->random == nullptr)//此处是bug,如果不判断node->random为nullptr,则指向null时越界
            {
                next->random = node->random->next;
            }

            node = next->next;//往后循环2位
        }
    }
    
    //拆分List
    RandomListNode* splitList(RandomListNode* pHead)
    {
        if(pHead == nullptr || pHead->next == nullptr)
            return nullptr;
        RandomListNode* ListOdd = pHead;
        RandomListNode* ListEven = pHead->next;
        RandomListNode* head = ListEven;//决定返回奇数还是偶,但其实原有的就是奇数
        //循环拆分(每轮4个),奇数指向奇数偶数指向偶数,nullptr时退出循环
        while(ListEven != nullptr)
        {
            //处理奇数,赋值并后移
            ListOdd->next = ListEven->next;
            ListOdd = ListOdd->next;
            
            //处理偶数
            //此时,如果ListOdd为nullptr,ListOdd->next越界!需要将偶数赋值为nullptr
            if(ListOdd == nullptr)
                ListEven->next = nullptr;
            else
                ListEven->next = ListOdd->next;
            ListEven = ListEven->next;
        }
        return head;
    }
};


6.两个链表的第一个公共结点(公共结点后肯定就相同了)

(方法1 串联起来然后遍历 方法2 裁去长链表长部分,等长遍历,相同则为公共结点)

剑指Offer(三十六):两个链表的第一个公共结点

  //找到第一个公共结点:公共结点后都是相同的了,因为next指针也相同
  //方法1:将两个链表连接起来,然后依次遍历,最终总能重合!
  //方法2:去掉长的链表的前部分,使相同长度,然后遍历下去
  int getLength(ListNode* pHead)
  {
	int length = 0;
	while(pHead != nullptr)
	{
		++length;
		pHead = pHead->next;
	}
	return length;
  }
  ListNode* firstCommonNode(ListNode* pHead1, ListNode* pHead2)
  {
	int diff = getLength(pHead1) - getLength(pHead2);
	ListNode* longNode = (diff>0)?pHead1:pHead2;//找到长的一个链表
	ListNode* shortNode = (diff<=0)?pHead1:pHead2;//找到短的链表
	int absDiff = abs(diff);//获取绝对值,用于cut这个值
	for(int i = 0;i<absDiff;++i)
	{
		longNode = longNode->next;
	}
	while(longNode != nullptr && shortNode != nullptr)
	{
		if(longNode == shortNode)
			break;
		longNode = longNode->next;
		shortNode = shortNode->next;
	}
	return longNode;
  }


7.链表中环的入口结点

  • 有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。
  • 如何判断一个链表是否存在环?设定两个指针slow,fast,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
  • 如果链表存在环,如果找到环的入口点?当fast若与slow相遇时,slow肯定没有走遍历完链表或者恰好遍历一圈(整个是一个环)。于是我们从链表头与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。、

推导算法:

设快指针为p2,慢指针为p1,环长度为n,p1走过的路程为s

p2 = 2*p1

p = p + n(根据环路特性,所以相遇的点肯定如下:p2为p1加上n)

p2 = s+n

p1 = s

推导公式得出:

s = n

  • 剑指Offer(五十五):链表中环的入口结点

环形链表
 

  //链表中环的入口结点
  //step1:使用快慢指针判断是否有环:有则返回碰撞点
  //setp2:碰撞结点和初始结点递归,相遇结点为环入口(因为相差n为环的长度)
  //step1
  ListNode* getCycle(ListNode* pHead)
  {
	ListNode* slowHead = pHead;
	ListNode* fastHead = pHead;
	while(fastHead != nullptr && fastHead->next != nullptr)
	{
		fastHead = fastHead->next->next;
		slowHead = slowHead->next;
		if(slowHead == fastHead)
			return fastHead;
	}
	return nullptr;//表示没有环
  }
  //step2
  ListNode* getCycleEntry(ListNode* pHead)
  {
	ListNode* meetHead = getCycle(pHead);
	if(meetHead == nullptr)
	{
		cout<<"without cycle!"<<endl;
		return nullptr;
	} else {
		while(meetHead != pHead)
		{
			meetHead = meetHead->next;
			pHead = pHead->next;
		}
		return pHead;
	}
  }


8.删除链表中重复的结点

1->2->3->3->4->4->5 处理后为 1->2->5。  

特殊:1  -> 1         1,1,1->nullptr    1,1,1,2 ->2

1. 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况

2.设置 pre ,last 指针, pre指针指向当前确定不重复的那个节点,而last指针相当于工作指针,一直往后面搜索。

  //删除重复多余的结点
  //考虑头结点需要删除的情况
  ListNode* deleteRepeatNode(ListNode* pHead)
  {
	ListNode* pre = pHead;
	while(pre != nullptr &&pre->next != nullptr)
	{
		ListNode* cur = pre->next;
		if(cur->val == pre->val)
		{
			pre->next = cur->next;
			cout<<pre->val<<cur->val<<endl;
		//	delete cur;
		//	cur = nullptr;
		}
		pre = pre->next;
	}
	return pHead;
  }
  
//删除重复结点,包含自身
//用两个指针,pre为非重复的结点,cur是接下来遍历的结点
//2种情况:1.有重复,遍历cur到最后重复的,将pre指向cur->next,也就跳过了
//2.没有重复,cur和pre分别向后移
//注意点:1.新增头结点,用来删除开始就是重复的情况
//2.鲁棒性,用next指针前都要检测,并且放&&前面
//3.返回值需要不带头
ListNode* deleteDuplication(ListNode* pHead)
{
	if(pHead == nullptr || pHead->next == nullptr)
		return nullptr;
	//以下为bug代码:未考虑 {1,1,1,2},会返回{1,2}
	//需要新建一个头结点来避免该情况
	/*
    ListNode* result = pHead;
	ListNode* pre = pHead;
	ListNode* cur = pHead->next;
	*/
	ListNode* result = new ListNode(-1);
	result->next = pHead;
	ListNode* pre = result;
	ListNode* cur = result->next;
	while(cur != nullptr)
	{
		if((cur->next != nullptr) && (cur->val == cur->next->val))
		{
			//找到下一个没有重复的结点,特殊情况,到尾巴时,需要都删除,next->next要为nullptr
			//出去条件:如果相等,但是下一个为nullptr!也就是尾结点
			while((cur->next != nullptr) &&(cur->val == cur->next->val))
            {
				cur = cur->next;
            }
			pre->next = cur->next;
            cur = cur->next;
		} else {
		    pre = pre->next;
            cur = cur->next;
        }
    }
	//return result; //bug会返回带头结点
	return result->next;//返回未带头结点
}
#include<iostream>
#include<stack>
#include<vector>

using namespace std;

  struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(){};
        ListNode(int x) :
              val(x), next(NULL) {
        }
  };
  
  //尾插法:包含头结点
  ListNode* insertListToEnd(ListNode* list, int val)
  {
	ListNode* node = new ListNode;
	node->val = val;
	node->next = nullptr;
	if (list == nullptr)
	{
		//增加头结点和第一个结点
		ListNode* result = new ListNode;
		result->next = node;
		return result;
	}
	ListNode* temp = list;
	while(temp->next != nullptr)
	{
		temp = temp->next;
	}
	temp->next = node;
	return list;
  }
  
  //没有头结点的头插法
  ListNode* insertListToFront(ListNode* list, int val)
  {
	ListNode* node =new ListNode(val);
	node->next = list;
	return node;
  }
  //有头结点,head永远不为nullptr,head->next为nullptr时,链表为空
  ListNode* insertListToFrontWithHead(ListNode* list, int val)
  {
	if(list == nullptr)
	{
		//代表还没有头结点
		list = new ListNode;
		list->next = nullptr;
	}
	//将头结点之后赋给新结点,然后头结点下一个指向新结点
	ListNode* node = new ListNode(val);
	node->next = list->next;
	list->next = node;
	return list;
  }
  
  //包含头结点的打印
  void printList(ListNode* list)
  {
	if (list == nullptr)
	{
		cout<<"without head ,error list"<<endl;
		return;
	}
	ListNode* temp = list->next;
	while(temp != nullptr)
	{
		cout<<" "<<temp->val;
		temp = temp->next;
	}
	cout<<endl;
  }
  //未包含头结点的打印
  void printListWithoutHead(ListNode* list)
  {
	if (list == nullptr)
	{
		cout<<"without head ,error list"<<endl;
		return;
	}
	ListNode* temp = list;
	while(temp != nullptr)
	{
		cout<<" "<<temp->val;
		temp = temp->next;
	}
	cout<<endl;
  }
  
  vector<int> printListFromTailToHead(ListNode* list)
  {
	stack<ListNode*> sta;
	ListNode* temp = list->next;
	while(temp!=nullptr)
	{
		sta.push(temp);
		temp = temp->next;
	}
	vector<int> result;
	while(!sta.empty())
	{
		temp = sta.top();
		result.push_back(temp->val);
		sta.pop();
	}
	return result;
  }
  
  ListNode* reverseList(ListNode* list)
  {
	ListNode* pre = nullptr;
	ListNode* cur = list->next;//b包含头结点
	ListNode* next = nullptr;
	while(cur != nullptr)
	{
		next = cur->next;
		cur->next = pre;
		pre = cur;
		cur = next;
	}
	list->next = pre;
	return list;
  }
 
   //递归处理:递归两个结点排序
  ListNode* merge(ListNode* pHead1, ListNode* pHead2)
  {
	ListNode* pMergeHead = nullptr;
	//终结条件:此时包含3种情况,1或2为空返回非空,都为空返回空
	if((pHead1 == nullptr) || (pHead2 == nullptr))
	{
		ListNode* result = ((pHead1 != nullptr)?pHead1:pHead2);
		return result;
	}
	
	//递归基:返回小的一个结点,并递归下一个结点来获取小的结点。其实就是两个数组排序
	if(pHead1->val < pHead2->val)
	{
		pMergeHead = pHead1;
		pMergeHead->next = merge(pHead1->next, pHead2); 

	} else {
		pMergeHead = pHead2;
		pMergeHead->next = merge(pHead1, pHead2->next);
	}
	return pMergeHead;
  }
  
  ListNode* mergenonRecursion(ListNode* pHead1, ListNode* pHead2)
  {
	if(pHead1 ==nullptr || pHead2 == nullptr)
	{
		return ((pHead1 !=nullptr)?pHead1:pHead2);
	}

	ListNode* node = new ListNode;
	ListNode* pMergeHead = node;//需要返回的结果

	//此处使用&&,只要有一个循环完,剩余的放最后就行
	while(pHead1!=nullptr && pHead2 != nullptr)
	{
		//精彩的参数传递!:先操作node指向地址的值(当前结点),next指向下一个小结点.
		//然后更改node指向下一个小结点,最后移动pHead!
		if(pHead1->val < pHead2->val)
		{
			node->next = pHead1;//此处是修改地址区的值,意思是最小结点的下一个指向位置,node不停变换为最小结点
			node = pHead1;//node更改为最小结点
			pHead1 = pHead1->next;//移动pHead,因为使用过了
			
		} else {
			node->next = pHead2;
			node = pHead2;
			pHead2 = pHead2->next;
		}
	}
	//最后,将剩余的放到最后即可
	if(pHead1 !=nullptr || pHead2 != nullptr)
	{
		node->next = ((pHead1 !=nullptr)?pHead1:pHead2);
	}
	return pMergeHead;
	
  }
  
  //两种方法:递归  非递归
  ListNode* merge2List(ListNode* list1, ListNode* list2)
  {
	ListNode* result = new ListNode;
	ListNode* pHead1 = list1->next;
	ListNode* pHead2 = list2->next;
	result->next = merge(pHead1, pHead2);
	return result;
  }
  
  //深拷贝链表
  ListNode* copyList(ListNode* pHead)
  {
	if(pHead == nullptr)
		return nullptr;
	ListNode* node = new ListNode();
	ListNode* copyHead = node;
	//包含头结点,所以需要跳过phead,从next开始
	while(pHead->next != nullptr)
	{
		pHead = pHead->next;
		node -> next = new ListNode(pHead->val);
		node = node ->next;
		
	}
	return copyHead;
  }
  //拆分链表(分为奇偶项)
  ListNode* splitList(ListNode* pHead)
  {
	  //如果全空或只有一个元素,则返回该链表
	  if(pHead == nullptr || pHead->next == nullptr)
		  return pHead;
      ListNode* List1 = pHead;//奇数链表
      ListNode* List2 = pHead -> next;//偶数链表
	  ListNode* splitHead = List2;//返回的是技术还是偶数
	  //此时如果只有3个元素,List1(为nullptr)->next(会报错吧?)
      while(List2 != nullptr)
      {
	    List1->next = List2->next;
	    List1 = List1->next;
	    //此处防止奇数次链表进来,开始没考虑到
	    if(List1 == nullptr)
	        List2->next = nullptr;
	    else
	        List2->next = List1->next;
	    List2 = List2->next;
      }
	  return splitHead;
  }
  
   //深拷贝并连接链表
  ListNode* copyLinkList(ListNode* pHead)
  {
  	if(pHead == nullptr)
  		return pHead;
	//ListNode* node = nullptr;
	ListNode* result = pHead;
	while(pHead != nullptr)
	{
		//相当于指定位置插入一个链表算法,不过需要循环插入,然后移动2格!
		ListNode* node = pHead->next;//将后面的保存下来
		pHead->next = new ListNode(pHead->val);//拷贝新的链表到next
		pHead = pHead->next;//移动到新增的上面
		pHead->next = node;//新增的next指向前面保存的
		pHead = pHead->next;//再往后移动,完成此次循环,进入下次循环初始条件
	}
	return result;
  }
  
  //找到第一个公共结点:公共结点后都是相同的了,因为next指针也相同
  //方法1:将两个链表连接起来,然后依次遍历,最终总能重合!
  //方法2:去掉长的链表的前部分,使相同长度,然后遍历下去
  int getLength(ListNode* pHead)
  {
	int length = 0;
	while(pHead != nullptr)
	{
		++length;
		pHead = pHead->next;
	}
	return length;
  }
  ListNode* firstCommonNode(ListNode* pHead1, ListNode* pHead2)
  {
	int diff = getLength(pHead1) - getLength(pHead2);
	ListNode* longNode = (diff>0)?pHead1:pHead2;//找到长的一个链表
	ListNode* shortNode = (diff<=0)?pHead1:pHead2;//找到短的链表
	int absDiff = abs(diff);//获取绝对值,用于cut这个值
	for(int i = 0;i<absDiff;++i)
	{
		longNode = longNode->next;
	}
	while(longNode != nullptr && shortNode != nullptr)
	{
		if(longNode == shortNode)
			break;
		longNode = longNode->next;
		shortNode = shortNode->next;
	}
	return longNode;
  }
  
  //链表中环的入口结点
  //step1:使用快慢指针判断是否有环:有则返回碰撞点
  //setp2:碰撞结点和初始结点递归,相遇结点为环入口(因为相差n为环的长度)
  //step1
  ListNode* getCycle(ListNode* pHead)
  {
	ListNode* slowHead = pHead;
	ListNode* fastHead = pHead;
	while(fastHead != nullptr && fastHead->next != nullptr)
	{
		fastHead = fastHead->next->next;
		slowHead = slowHead->next;
		if(slowHead == fastHead)
			return fastHead;
	}
	return nullptr;//表示没有环
  }
  //step2
  ListNode* getCycleEntry(ListNode* pHead)
  {
	ListNode* meetHead = getCycle(pHead);
	if(meetHead == nullptr)
	{
		cout<<"without cycle!"<<endl;
		return nullptr;
	} else {
		while(meetHead != pHead)
		{
			meetHead = meetHead->next;
			pHead = pHead->next;
		}
		return pHead;
	}
  }
  
  //删除重复多余的结点
  //考虑头结点需要删除的情况
  ListNode* deleteRepeatNode(ListNode* pHead)
  {
	if(pHead == nullptr)
		return nullptr;
	
	ListNode* pre = pHead;
	
	//ListNode* next = pHead->next;
	while(pre != nullptr &&pre->next != nullptr)
	{
		ListNode* cur = pre->next;
		//next = cur->next;
		if(cur->val == pre->val)
		{
			pre->next = cur->next;
			cout<<pre->val<<cur->val<<endl;
		//	delete cur;
		//	cur = nullptr;
		}
		pre = pre->next;
	}
	return pHead;
  }

//删除重复结点,包含自身
//用两个指针,pre为非重复的结点,cur是接下来遍历的结点
//2种情况:1.有重复,遍历cur到最后重复的,将pre指向cur->next,也就跳过了
//2.没有重复,cur和pre分别向后移
//注意点:1.新增头结点,用来删除开始就是重复的情况
//2.鲁棒性,用next指针前都要检测,并且放&&前面
//3.返回值需要不带头
ListNode* deleteDuplication(ListNode* pHead)
{
	if(pHead == nullptr || pHead->next == nullptr)
		return nullptr;
	//以下为bug代码:未考虑 {1,1,1,2},会返回{1,2}
	//需要新建一个头结点来避免该情况
	/*
    ListNode* result = pHead;
	ListNode* pre = pHead;
	ListNode* cur = pHead->next;
	*/
	ListNode* result = new ListNode(-1);
	result->next = pHead;
	ListNode* pre = result;
	ListNode* cur = result->next;
	while(cur != nullptr)
	{
		if((cur->next != nullptr) && (cur->val == cur->next->val))
		{
			//找到下一个没有重复的结点,特殊情况,到尾巴时,需要都删除,next->next要为nullptr
			//出去条件:如果相等,但是下一个为nullptr!也就是尾结点
			while((cur->next != nullptr) &&(cur->val == cur->next->val))
            {
				cur = cur->next;
            }
			pre->next = cur->next;
            cur = cur->next;
		} else {
		    pre = pre->next;
            cur = cur->next;
        }
    }
	//return result; //bug会返回带头结点
	return result->next;//返回未带头结点
}
  int main() {
  ListNode* head;
  head = insertListToFrontWithHead(head,5);
  head = insertListToEnd(head,3);
  head = insertListToFrontWithHead(head,9);
  head = insertListToEnd(head,6);
  head = insertListToFrontWithHead(head,4);
  printList(head);

  head = reverseList(head);
  printList(head);
  
  vector<int> reserve = printListFromTailToHead(head);
  for(auto it = reserve.begin();it!=reserve.end();++it)
  {
	  cout<<" "<<*it;
  }
  cout<<endl;

	
	//合并两个结点
	/*
	ListNode* phead1;
	ListNode* phead2;
	ListNode* merge;
	phead1 = insertListToEnd(phead1,3);
	phead1 = insertListToEnd(phead1,7);
	phead1 = insertListToEnd(phead1,9);
	phead1 = insertListToEnd(phead1,12);
	
	phead2 = insertListToEnd(phead2,4);
	phead2 = insertListToEnd(phead2,11);
	phead2 = insertListToEnd(phead2,22);
	phead2 = insertListToEnd(phead2,25);
	printList(phead1);
	printList(phead2);
	merge = merge2List(phead1, phead2);
	printList(merge);
	//merge = mergenonRecursion(phead2,phead1);
	//printList(merge);
	*/

	//简单链表深拷贝
	/*
	ListNode* copy = copyList(head);
	printList(copy);
	cout<<"addr is diff:"<<&(copy->next)<<" "<<&(head->next)<<endl;
	*/
	
	//拆分链表
	printListWithoutHead(head);
	ListNode* split = splitList(head->next);
	printListWithoutHead(split);
	//拷贝链表到后面
	ListNode* copy = copyLinkList(head);
	printListWithoutHead(copy);
	
	//删除重复多余结点
	ListNode* dele = deleteRepeatNode(copy);
	printListWithoutHead(dele);	
	
  return 0;
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值