大一计算机的自学总结:链表的相关操作

前言

以下是对两个链表进行的一些操作,因为分开写感觉有点水(bushi),所以就合在一篇里了。

其中引入的“LinkedListFunction”函数在我“单双链表的反转”中有。

大一计算机的自学总结:单双链表的反转

一、合并两个有序链表

#include
#include"LinkedListFunction.h"
using namespace std;

//合并两个有序链表
List merge(List &list1,List &list2)
{
	List list;
	list.head=list1.head->value<=list2.head->value?list1.head:list2.head;
	Node* p1=list.head->next;
	Node* p2=list.head==list1.head?list2.head:list1.head;
	list.tail=list.head;
	
	while(p1!=NULL&&p2!=NULL)
	{
		if(p1->value>=p2->value)
		{
			list.tail->next=p2;
			p2=p2->next;
		}
		else
		{
			list.tail->next=p1;
			p1=p1->next;
		}
		list.tail=list.tail->next;
	}
	list.tail->next=p1!=NULL?p1:p2;
	while(list.tail->next!=NULL)
	{
		list.tail=list.tail->next;
	}

	return list;
}

int main()
{
	List list1,list2;
	list1.head=list1.tail=NULL;
	list2.head=list2.tail=NULL;
	
	int n;
	cout<<"Add n to list1:"<>n;
        if (n != -1)
        {
            add(list1, n);
        }
    } while (n != -1);
	cout<<"Add n to list2:"<>n;
        if (n != -1)
        {
            add(list2, n);
        }
    } while (n != -1);
    cout<<"Before merge:"<

主函数没什么好说的,重点是merge函数。

首先定义list,为合并后的链表,先判断list1和list2的头结点的大小,并将小的结点设置为合并后list的头结点。

之后为了分别对两个链表的结点进行操作,需要定义两个指针p1和p2,并让p1指向头结点的下一个结点,那么p2就是另一个链表的头结点。

然后采用尾插法,当p1和p2的下一个结点均不为NULL时,通过比较p1和p2所指结点的值的大小,将结点连接到list.tail上。

最后,当其中一个链表结束,将list.tail连到另一个链表,并将其移到最后。

二、两个链表相加(高精度加法)

这里,默认两个链表中的数和结果链表中的数是逆置后的。若是想要反转输出,正好可以用到上篇文章中的单链表的反转。大一计算机的自学总结:单双链表的反转

#include
#include"LinkedListFunction.h"
using namespace std;

//两链表相加
List add(List &list1,List &list2)
{
	List list;
	list.head=list.tail=NULL;
	
	int t=0;
	Node* p1=list1.head;
	Node* p2=list2.head;
	while(p1!=NULL||p2!=NULL)
	{
		if(p1!=NULL)
		{
			t+=p1->value;
			p1=p1->next;
		}
		if(p2!=NULL)
		{
			t+=p2->value;
			p2=p2->next;
		}
		add(list,t%10);
		t/=10;
	}
	if(t!=0)
	{
		add(list,t);
	}
	return list;
}

int main()
{
	List list1,list2;
	list1.head=list1.tail=NULL;
	list2.head=list2.tail=NULL;
	
	int n;
	cout<<"Add n to list1:"<>n;
        if (n != -1)
        {
            add(list1, n);
        }
    } while (n != -1);
	cout<<"Add n to list2:"<>n;
        if (n != -1)
        {
            add(list2, n);
        }
    } while (n != -1);
    cout<<"Before add:"<

 我感觉也没啥好说的(),挺简单的,原理和我“高精度加法”那篇文章中一样,就是数组改成链表了而已。大一计算机的自学总结:高精度算法——加法

三、划分链表

题意为,输入一个数x,将链表中小于x的结点和大于等于x的结点分开,不改变原链表中结点顺序,最后相连。

#include
#include"LinkedListFunction.h"
using namespace std;

//划分两链表
void partition(List &list,int x)
{
	List small,big;
	small.head=small.tail=NULL;
	big.head=big.tail=NULL;
	Node* p=list.head;
	Node* next=NULL;
	
	while(small.tail!=list.tail&&big.tail!=list.tail)
	{
		next=p->next; 
		p->next=NULL;//先让此结点与下一个结点断连
		if(p->valuenext=p;
				small.tail=small.tail->next;
			}
		}
		else
		{
			if(big.head==NULL)
			{
				big.head=p;
				big.tail=big.head;
			}
			else
			{
				big.tail->next=p;
				big.tail=big.tail->next;
			}
		}
		p=next;//断连后跳到下一个结点 
	}
	
	small.tail->next=big.head;
	
	list.head=small.head;
	list.tail=big.tail;
}

int main()
{
	List list;
	list.head=list.tail=NULL;
	
	int n;
	cout<<"Add n to list:"<>n;
        if (n != -1)
        {
            add(list, n);
        }
    } while (n != -1);

	cout<<"Before partition:"<

 根据题目要求,设置small和big,代表小于x的部分和大于等于x的部分。然后为了标记当前结点和下一个结点并将其断开原有的连接,还需要引入p和next两个指针。

注意,这一步很重要,如果不在每一步断开并重连,划分后的链表会循环连接。

之后,当两链表都没到list.tail,先移动next指针到p指针所指结点的下一个,保存p所指结点的下一个结点的位置以便p在所指结点与下一个结点断连后仍能跳到下一个结点,然后就可以将p所指结点的next指针断开,再根据与x的大小关系重新进行连接,然后把p移动到next。这里重新连接的思路类似于添加链表。具体内容在我“初见链表”的文章里。大一计算机的自学总结:初见链表

最后,将small的tail连接到big的head并更新list.head和list.tail。

总结

重点是合并两个链表和划分链表的思路。合并链表主要是辅助指针的使用。划分链表主要是尾插法,需要重点注意的是,像这种对一个链表重新连接操作的问题,一定要先标记下一个结点并将原链表断连,之后再进行重连的操作

END

你可能感兴趣的:(链表,数据结构,c++,算法)