线性表应用

旧街凉风 提交于 2020-01-30 09:32:44

合并有序顺序表

将两个有序(非递减)顺序表La和Lb合并为一个新的有序(非递减)顺序表。

void MergeSqlist(SqList La, SqList Lb, SqList &Lc){
	int i,j,k;
	i=j=k=0;
	Lc.length=La.length+Lb.length;
	Lc.elem=new int[Lc.length];
	while(i<La.length&&j<Lb.length){
		if(La.elem[i]>Lb.elem[j]){
			Lc.elem[k++]=Lb.elem[j++];
		}else{
			Lc.elem[k++]=La.elem[i++];
		}
	}
	while(i<La.length)Lc.elem[k++]=La.elem[i++];
	while(j<Lb.length)Lc.elem[k++]=Lb.elem[j++];
	
}

合并有序链表

将两个有序(非递减)单链表La和Lb合并为一个新的有序(非递减)单链表。

解题思路:

链表合并不需要再创建空间,只需要“穿针引线”,把两个单链表中的节点按非递减的顺序串联起来即可。

注意:单链表的头指针不可以移动,一旦头指针丢失,就找不到该单链表了,因此需要辅助指针。

1)初始化。设置3个辅助指针p,q,r,其中p,q分别指向La和Lb链表的当前比较位置,新链表头指针Lc指向La,当作合并后的头节点。r指向Lc的当前最后一个节点,利用r指针“穿针引线”

2)穿针引线。比较元素大小,将较小元素用r串起来

3)串联剩余部分。p指针不为空,用r指针将p串联起来,即r->next=p,注意这里只是把这个指针连起来即可,剩余的节点不需要在处理

void mergelinklist(LinkList La,LinkList Lb,LinkList &Lc)
{
    LinkList p,q,r;
    p=La->next; //p指向La的第一个元素
    q=Lb->next; //q指向Lb的第一个元素
    Lc=La;      //Lc指向La的头结点
    r=Lc;       //r指向Lc的尾部
    while(p&&q)
    {
        if(p->data<=q->data)//把p指向的结点串起来
        {
            r->next=p;
            r=p;
            p=p->next;
        }
        else             //把q指向的结点串起来
        {
            r->next=q;
            r=q;
            q=q->next;
        }
    }
    r->next=p?p:q;//相当于if(p) r->next=p; else r->next=q;
    delete Lb;
}

 

就地逆置单链表

将带有头节点的单链表就地逆置。即元素的顺序逆转,而辅助空间复杂度为O(1)

解题思路:

充分利用原有的存储空间,通过修改指针实现单链表的就地逆置。还记得吗?头插法创建单链表得到的序列正好是逆序,那么我们就利用头插法建表的思路,实现就地逆置

注意:在修改指针之前,一定要用一个辅助指针记录断点,否则后面这一部分就会遗失,再也找不到了。

1)首先用指针指向第一个元素节点,然后将头节点的next域置空。头节点的next域置空:L->next=NULL

2)将p节点用头插法插入链表L中,插入之前用q指针记录断点

void reverselinklist(LinkList &L)
{
    LinkList p,q;
    p=L->next; //p指向L的第一个元素
    L->next=NULL; //头结点的next域置空:
    while(p)
    {
        q=p->next;//q指向p的下一个结点,记录断点;
        p->next=L->next; //头插法,将L的下一个结点地址赋值给p的next域
        L->next=p; //将p结点地址赋值给L的next域
        p=q;//指针后移,p指向q;
    }
}

 

查找链表的中间节点

带有头节点的单链表L,设计一个尽可能高效的算法求L中的中间节点。

解题思路:此类题型可以使用快慢指针来解决。一个快指针,一个慢指针,快指针走两步,慢指针走一步。当快指针指向结尾的时候,慢指针刚好指向中间节点。

复杂度:算法对单链表进行了一趟扫描,如果L的长度为n,则时间复杂度为O(n),没有使用其他辅助空间,只是几个辅助指针变量,因此空间复杂度为O(1)

LinkList findmiddle(LinkList L)
{
	LinkList p,q;
	p=L;//p为快指针,初使时指向L 
	q=L;//q为慢指针,初使时指向L
	while(p!=NULL&&p->next!=NULL){
		p=p->next->next;//快指针一次走两步 
		q=q->next;
	} 
	return q;//返回中间节点指针 
} 

查找倒数第k个节点

仍然可以使用快慢指针,慢指针不要动,快指针先走k−1步,然后两个指针一起以同样的速度走。当快指针走到终点时,慢指针正好停留在倒数第k个节点

复杂度:

算法对单链表进行了一趟扫描,如果L的长度为n,则时间复杂度为O(n),),没有使用其他辅助空间,只是几个辅助指针变量,因此空间复杂度为O(1)

LinkList findk(LinkList L,int k)
{
    LinkList p,q;
    p=L->next; //p为快指针,初始时指向第一个数据结点
    q=L->next; //q为慢指针,初始时指向第一个数据结点
    while(p->next!=NULL)
    {
        if(--k<=0)//k减到0时,慢指针开始走 
            q=q->next;//q为慢指针
        p=p->next; //p为快指针;
    }
    if(k>0)
        return NULL;
    else
        return q;//返回中间结点指针
}

删除链表中的重复元素

题目:用单链表保存m个整数,节点的结构为(data,next),且|data|<n(n为正整数)。现要求设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的节点,仅保留第一次出现的节点而删除其余绝对值相等的节点。

解题思路:

本题数据大小有范围限制,因此可以设置一个辅助数组记录该数据是否已出现,如果已出现,则删除;如果未出现,则标记。一趟扫描即可完成。

复杂度:

根据题意,单链表中保存m个绝对值小于等于n的整数,因此链表元素个数为m,算法从头到尾扫描了一遍链表,时间复杂度为O(m);采用了辅助数组flag[],因为n为正整数,不包括0,所以0空间不用,需要分配n+1个辅助空间,因此空间时间复杂度为O(n)

1)设置一个辅助数组flag[],因为n为正整数,不包括0,所以0空间不用。需要分配n+1个辅助空间,初始化时都为0,表示这些数还未出现过

2)设置指针指向头节点,检查第一个数据元素是否已出现过。令x=abs(p->next->data),如果已出现过(flag[x]=1),则删除该节点;如果该节点数据元素未出现过,则标记flag[x]=1,p指针向后移动,直到处理完毕

void Deleterep(LinkList &L)//删除重复元素
{
    LinkList p,q;
	int x;
	//定义flag数组,分配n+1个空间,0空间未用 ,*表示访问指针中地址的值 
	int *flag=new int [n+1];
	for(int i=0;i<n+1;i++){//初始化 
		flag[i]=0;
	} 
	p=L;
	while(p->next!=NULL){
		x=abs(p->next->data);
		if(flag[x]==0){//未出现过 
			flag[x]=1;//标记出现过 
			p=p->next;//指针后移 
		}else{
			q=p->next;//q指向p的下一个节点 
			p->next=q->next;//删除重复元素
			delete q;//释放空间 
		} 
	}
	delete []flag; 
}

线性表学习秘籍

顺序表

1)位序和下标差1,第i个元素的下标为i−1

2)移动元素时,特别注意先后顺序,以免覆盖。

例如,在第i个位置插入一个元素e,需要从需要从最后一个元素开始,后移一位,直到把第i个元素也后移一位,然后把e放入第i个位置,如图

例如,删除第i个元素,从i+1个元素开始前移……直到把第n个元素也前移一位,即可完成删除操作,如图

3)交换元素、有序合并需要借助辅助空间。

链表

1) 对于有关指针的赋值语句,容易混淆。等号的右侧是节点的地址,等号的左侧是节点的指针域

2) 修改指针顺序:先修改没有指针标记的那一端

3)建立链表的两种方法:头插法、尾插法。头插法是逆序建表,尾插法是正序建表。

4)链表逆置、归并不需要额外空间,属于就地操作

5)快慢指针法:快慢指针可以解决很多问题,如链表中间节点、倒数第k个节点、判断链表是否有环、环的起点、公共部分的起点等。

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!