线性表的应用(一)

线性表的应用(一)

(1)设计一个算法,将顺序表逆置。
(2)已知长度为 n 的线性表 A 采用顺序存储结构,请写一时间复杂度为 O(n)、空间复杂度为 O(1)的算法,该算法删除线性表中所有值为 item 的数据元素。
(3)将两个递增的有序链表合并为一个递增的有序链表。要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。表中不允许有重复的数据。
(4)已知两个链表 A 和 B 分别表示两个集合,其元素递增排列。请设计算法求出 A 与 B的交集,并存放于 A 链表中。
(5)设计一个算法,通过遍历一趟,将链表中所有结点的链接方向逆转,仍利用原表的存储空间。
(6)设计一个算法,删除递增有序链表中值大于 mink 且小于 maxk 的所有元素(mink和 maxk 是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。
(7)已知 p 指向双向循环链表中的一个结点,其结点结构为 data、prior、next 三个域,写出算法 change§,交换 p 所指向的结点和它的前驱结点的顺序。

(1)顺序表逆置。
算法思想:将第一个元素与最后一个元素交换,第二个与倒数第二个,以此类推。

 void Reverse(SqList &L)
 {
    ElemType temp;
	for(i = 0;i < L.length/2;i++)//循环条件为长度的一半,才能实现逆置
	{
		temp = L.elem[i];
		L.elem[i] = L.elem[L.length - 1 - i];
		L.elem[L.length - 1 - i] = temp;
	}
} 

(2)删除顺序表中所有值为 item 的数据元素。
算法思想:直接对原顺序表进行赋值,遇到第一个item,就前移一位,遇到第二个就前移两位,以此类推。

void  DeleteItem(SqList L, ElemType item) 
 {  
	 n = L.length;
	 /* 此步不能省,长度变化了,
	 循环判断条件不能直接用j < L.length */
	 for(i = 0,j = 0;j < n;i++,j++)   
	 {     
		 if(L.elem[j]!=item)   
		 { 
			 L.elem[i]=L.elem[j];//L.elem[i]为“新”顺序表元素,L.elem[j]为原来顺序表元素
		 }
		 else
		 { 
			 j++;//遇到item,原顺序表元素直接跳到下一个元素,不进行赋值
			 L.length--;//长度-1
		 }
	 }
 }  

该算法时间复杂度为 O(n)、空间复杂度为 O(1)。

(3)两个有序递增链表的合并。
算法思想:两个有序递增链表分别为A、B,合并为C。链表C使用A(A、B都行)的头节点。

  • 先将A、B中的第一个元素进行比较。
  • 假如A小,将C指向A,然后A后移,C后移。
  • 假如B小,将C指向B,然后B后移,C后移。
  • 两者相等,将C指向A,然后A后移,C后移,B后移。(B后移完成题目要求不能重复元素)
  • 当一个表到达表尾结点(为空),将非空表的剩余元素直接链接在 C的最后。

最后不要忘记释放B中相同元素的节点!!!

void MergeList(LinkList &A,LinkList &B,LinkList &C) 
{  
	/*链表的第一步操作一般都是记下第一个元素,
	方便后续操作,因为不能把头指针改变了*/
	pa = A->next;pb = B->next;
	C = pc = A;  //用 A 的 头结点作为 C 的头结点   
	while(pa && pb) 
	{
		if(pa->data < pb->data)//A小 
		{
			pc->next = pa;// 将C指向A 
			pc = pa;// C后移
			pa = pa->next;// A后移 
		}       
		else if(pa->data > pb->data) //B小 
		{
			pc->next = pb; // 将C指向B 
			pc = pb; // C后移
			pb = pb->next;// B后移 
		}        
		else //相等时,取A中的元素,删除B中的元素 
		{
			 pc->next = pa;//将C指向A 
			 pc = pa;// C后移 
			 pa = pa->next;// A后移       
			 q = pb->next;//记下B的后继,用于释放
			 free(pb) ; //释放
			 pb = q; // B后移
		}      
	}  
	pc->next = pa?pa:pb;  //将非空表的剩余元素直接链接在C的最后。         
	free(B);            //释放B的头结点 
}

如果允许有重复元素 :两者相等时,将C指向A,然后A后移,C后移,B后移 ,然后继续执行循环。

(4)两个有序递增链表的交集。
算法思想: 两个有序递增链表分别为A、B,交集为C。链表C使用A的空间。交集即取A中A、B相同元素,不相同元素节点释放。

  • 比较A、B元素,两者元素相同,将C指向A,然后A后移,C后移,B后移;
  • 不相同,C不做任何操作
  • 当某个表为空时,停止循环。

最后不要忘记释放未空表中剩余元素的节点!!!

void InterSection(LinkList &A, LinkList B)  
{    
	pc = A; pa = A->next;  
	pb = B->next;   
	while(pa&&pb) 
	{ 
		if(pa->data == pb->data)//两者元素相同       
		{ 
			pc->next = pa;// 将C指向A 
			pc = pa;// C后移 
			pa = pa->next;// A后移 
			pb = pb->next; // B后移  
		}   
		else if(pa->data < pb->data) //删除不在交集中的A中的元素  
		{
			q = pa;pa = pa->next;//删除时,一定要找到删除元素的后继
			free(q);
		} 
		else  
		{ 
			pb = pb->next; 
		} 
	} 
	while(pa) //释放未空表中剩余元素的节点
	{
		q = pa; pa = pa->next; free(q);
	}   
	pc->next=NULL; //表尾为空
}

如果求两个有序递增链表的 差集
算法思想: 两个有序递增链表分别为A、B,交集为C。链表C使用A的空间。仅由在 A 中出现而不在 B 中出现的元素构成集合C,即取A中A、B不相同元素,相同元素节点释放。

(5)链表逆置 。
算法思想:即链表前插法

  • 将链表 L 的头结点与链表的第一个元素结点断开;让 p 指向第一个元素结点,L 变成一个只有一个头结点的空链表。
  • 将 p 所指的链表中的各结点依次插在 L 的链头。
void  Inverse(LinkList &L)  
{      
	p = L->next;  //p为头节点
	L->next = NULL; //将头结点与第一个结点断开     
	while(p)  
	{
		q = p->next;    // q指向第一个元素        
		p->next = L->next;  //将 p 插入在头结点之 后          
		L->next = p;              
		p = q;      
	} 
}

(6)删除递增有序链表中值大于 mink 且小于 maxk 的所有元素。
算法思想:找第一个值大于 mink 的结点,然后删除在(mink,maxk)之间的所有结点。

void  delete_L( LinkList &L,int mink,int maxk) 
{ 
	if(L->next && mink < maxk)  
	{    
		p = L; 
		q = L->next;    
		while(q && q->data <= mink) //找第一个值大于 mink 的结点; 
		{      
			p = q;
			q = q->next; 
		}//跳出循环时,p为删除节点片段的前驱
		while (q && q->data < maxk) //删除在(mink,maxk)之间的所有结点    
		{    
			s = q; 
			q = q->next ; 
			free(s);     
		} 
		p->next = q; // q未删除节点片段的后继    
	} 
}

(7)交换双向链表的两个节点。

void Exchange(DuLinkList p) 
{ //p 是双向循环链表中的一个结点的指针,将p所指结点与其前驱结点交换。 
	q=p->prior; 
	q->prior->next=p; //q的前驱的后继变成p 
	p->prior=q->prior; //p的前驱变成q的前驱,相当于将q从链表中删除 
	q->prior=p; 
	q->next=p->next; 
	p->next->prior=q; 
	p->next=q; 
}
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值