单链表经典算法与时间复杂度分析

设计算法以删除链表中值为x的结点``
【算法描述】:
删除给定值的结点关键是寻找此结点和最终的释放内存。查找此结点需要一个循环,定义的指针p指向头结点因为不是双链表所以p每次的指向必须为直接前驱,循环控制条件是如果p的直接后继不是我们要找的值并且p不是最后一个结点,循环就可以继续,对应的跳出循环有两种情况,第一种是找到了,删除释放内存,没找到就返回false主函数里给用户提示信息。
【算法实现】:

bool DeleteElement(node *L, elementType x) //参数是单指针链表和要删除的元素X 
{
	node *p = L;   //定义一个指针p指向头结点(因为删除结点要指在被删除的直接前驱) 
	//注意循环体里的条件:p->next->data和x比较还是因为p必须指在被删除结点的前驱,另一个条件是p->next!=NULL即被删元素不能不存在 
	while(x!=p->next->data&&p->next!=NULL){
		p=p->next;
	}
	if(p->next==NULL){
		return false;
	}
	//执行删除操作 
	else{
		u = new node;
		u = p->next;
		p->next = u->next;
		delete u;   //释放结点防止内存泄露 
		return true;
	}
} 

假设递增有序的带头结点的单循环链表 A、B 分别表示两个集合,设计算法以求解 A= A∪B,并分析算法的时间复杂度
【算法描述】
原链表递增有序就需要利用这一个条件,集合的基本要求是不能存在两个相同的元素,每一个链表从受元素结点开始扫描,每扫描到一个元素就比较大小,从而分成三种情况,新链表采用尾插法,既可以调用尾插法的函数也可以直接写语句(语句比较简单),本算法采取了后者,由于是尾插,所以在所有的元素插入到新表之后要把新表的尾指针置空。
【算法实现】

int UniteList(node *A, node *B, node *&L)
{
	if(A->next==NULL||B->next==NULL){  //排除A或B表中有空表的情况 
		return 1;
	}
	else{
		node *s;   //新插入的元素结点 
		node *p;
		p = A->next;
		node *q;
		q = B->next;
		node *R;  //新表尾结点指针 
		R = L;
		while(p!=NULL&&q!=NULL){
			if(p->data==q->data){
				s = new node;
				s->data = p->data;
				R->next = s;
				R = s;   //移动尾指针 
				p = p->next;
				q = q->next;
			}
			else if(p->data>q->data){
				s = new node;
				s->data = q->data;
				R->next = s;
				R = s;
				q = q->next;
			}
			else{
				s = new node;
				s->data = p->data;
				R->next = s;
				R = s;
				p = p->next;
			}
		}
//把没有插入完的表逐一插入
while(p!=NULL){
				s = new node;
			    s->data = p->data;
		     	R->next = s;
			    R = s;
p = p->next;
		   } 
			while(q!=NULL){
				s = new node;
				s->data = q->data;
				R->next = s;
				R = s;
q = q->next;
			}
		R->next = NULL;  //最后把尾指针的next置空 
		return 2;
	}
} 

【时间复杂度分析】
本算法把两个链表所有的元素都扫描了一遍,所以时间复杂度为O(|A|+|B|)

设计算法将链表L就地逆置,即利用原表各节点的空间实现逆置
【算法分析】
就地逆置有多种方法,这里采取的是头插法,基本思想是保留原链表的头结点,先把头结点的指针域置空,用指针指住首元素结点,再用一个指针作为倒换的容器(类似于temp),从第一个元素开始逐一头插就会实现链表的逆置,头插每一个元素的步骤是先移动指针到下一个元素节点,然后把被插入元素的指针域赋值为头结点的指针域,再将头节点的next指向该结点。
【算法描述】

int InversionList(node *&L)  //指针的引用,回传逆置后的链表
{
	if(L->next==NULL||L->next->next==NULL){
		return 1;
	}
	else{
		node *p;   
		node *q;   //q作为交换的容器
		p = L->next;   //p指向首元素结点
		L->next = NULL;   //头结点的指针域置空
		while(p!=NULL)   //当链表没有扫描结束时
		{
//头插法依次插入元素结果就是逆置的
			q = p;
			p = p->next;
			q->next = L->next;
			L->next = q;
		}
		return 2;
	}
}

设计算法将两个递增有序带头结点的单链表A,B合并为一个递减有序的带头结点的单链表,并要求算法的时间复杂度为两个表长之和的数量级
【算法分析】
合并两个递增链表为一个递减链表,基本思想是比较之后进行头插(因为头插可以实现逆置),不是集合不需要去掉相同元素,首先排除两个表中有空表的情况,在插入时也可以调用头插函数,这里我是直接写了语句因为语句也比较简单,大循环退出后要把A表或者B表中没有插入完的元素逐一插入到新链表中。

【算法描述】

int Diminishmerger(node *A, node *B, node *&L)//(考虑如果在函数体内定义L该怎么写)
{
	if(A->next==NULL||B->next==NULL){  //排除A或B表中有空表的情况 
		return 1;
	}
	else{
		node *s;
		node *p;
		p = A->next;
		node *q;
		q = B->next;
		L->next = NULL;  //头结点指针域置空,为尾结点的指针域为空 
		while(p!=NULL&&q!=NULL){
			//由于不是集合因此相等时要全部插入 
			if(p->data==q->data){
				s = new node;
				s->data = p->data;
				s->next = L->next;
				L->next = s;
				s = new node;
				s->data = q->data;
				s->next = L->next;
				L->next = s;
				p = p->next;
				q = q->next;   //最后要都指向下一个结点 
			}
			else if(p->data<q->data){
				s = new node;
				s->data = p->data;
				s->next = L->next;
				L->next = s;
				p = p->next;
			}
			else{
				s = new node;
				s->data = q->data;
				s->next = L->next;
				L->next = s;
				q = q->next;
			}
		} 
		//处理没有扫描完的链表剩余部分 
		while(p!=NULL){
			s = new node;
			s->data = p->data;
			s->next = L->next;
			L->next = s; 
			p = p->next;
		}
		while(q!=NULL){
			s = new node;
			s->data = q->data;
			s->next = L->next;
			L->next = s;
			q = q->next;
		}
		return 2;
	}
}

【时间复杂度分析】
算法中三个循环把A,B两个链表全部都扫描了一遍,所以时间复杂度为两个表之和O(|A|+|B|)

你可能感兴趣的:(单链表经典算法与时间复杂度分析)