链表相关算法(链表相加, 链表的部分翻转,链表划分链表划分,排序链表中去重)

链表相加
  • 给定两个链表,分别表示两个非负整数。它 们的数字逆序存储在链表中,且每个结点只 存储一个数字,计算两个数的和,并且返回 和的链表头指针
    • 如:输入:2→4→3、5→6→4,输出:7→0→8
  • 问题分析
    • 输入:2->4->3、5->6->4,输出:7->0->8
    • 因为两个数都是逆序存储,正好可以从头向 后依次相加,完成“两个数的竖式计算”。
typedef struct tagSNode{
	int value;
	tagSnode *pNext;

	tagSNode(int v):value(v),pNext(NULL){}
}SNode;

int _tmain(int argc,_TCHAR* argv[]){
	SNode *pHead1 = new SNode(0);
	int i;
	for(i = 0;i<6;i++){
		SNode* p = new SNode(rand()%10)
		p->pNext = pHead1->pNext;
		pHead1->pNext = p;
	}
	SNode *pHead2 = new SNode(0);
	for(i=0;i<9;i++){
		SNode *p = new SNode(rand() % 10);
		p->pNext = pHead2->pNext;
		pHead2->pNext = p;
	}
	Print(pHead1);
	Print(pHead2);
	SNode *pSum = Add(pHead1,pHead2);
	Print(pSum);
	Destory(pHead1);
	Destory(pHead2);
	Destory(pSum);
	return 0;
}
SNode* Add(SNode* pHead1,SNode* pHead2){

	SNode * pSum = new SNode(0);
	SNode *pTail = pSum;//新节点插入到pTail的后面
	SNode *p1 = pHead1->pNext;
	SNode *p2 = pHead2->pNext;
	SNode *pCur;
	int carry = 0;//进位
	int value;
	while(p1 && p2){
		value = p1->value + p2.->value+carry;
		carry = value/10;
		value %= 10;
		pCur = SNode(value);
		pTail->pNext = pCur;//新节点链接到pTail后面
		pTail = pCur;
		p1 = p1->pNext;
		p2 = p2->pNext; 
	}
	//处理较长的链
	SNode *p = p1 ? p1 : p2;
	while(p){
		value = p->value+carry;
		carry = value/10;
		value %= 10;
		pCur = new SNode(value);
		pTail->pNext = pCur;//新节点链接到pTail的后面
		pTail = pCur;
		p1 = p1->pNext;
	}
	//处理可能存在的进位
	if(carry != 0)
		pTail->pNext = new SNode(carry);
	return pSum;
}
链表的部分翻转
  • 给定一个链表,翻转该链表从m到n的位置。 要求直接翻转而非申请新空间。
    • 如:给定1→2→3→4→5,m=2,n=4,返回 1→4→3→2→5。
    • 假定给出的参数满足:1≤m≤n≤链表长度
  • 分析
    • 空转m-1次,找到第m-1个结点,即开始翻转的第一个结点的前驱,记做head;
    • 以head为起始结点遍历n-m次,将第i次时, 将找到的结点插入到head的next中即可。
      • 即头插法
typedef struct tagSNode{
	int value;
	tagSnode *pNext;

	tagSNode(int v):value(v),pNext(NULL){}
}SNode;

int _tmain(int argc,_TCHAR* argv[]){
	SNode* pHead = new SNode(0);
	int i;
	for (i = 0; i < 10; ++i)
	{
		SNode *p = new SNode(rand() % 100);
		p->pNext = pHead->pNext;
		pHead->pNext = p;
	}
	Print(pHead);
	Reverse(pHead,4,8);
	Print(pHead);
	Destory(pHead);
	return 0;
}

void Destory(SNode* p){
	SNode *next;
	while(p){
		next = p->next;
		delete p;
		p = next;
	}
}

void Reverse(SNode* pHead,int from,int to){
	SNode *pCur = pHead->pNext;
	int i;
	for (i = 0; i < from-1; ++i)
	{
		pHead = pCur;
		pCur = pCur->next;
	}
	SNode *pPre = pCur;
	pCur = pCur->pNext;
	to--;

	SNode* pNext;
	for (; i < to; i++)//to-from
	{
		pNext = pCur->pNext;
		pCur->pNext = pHead->pNext;
		pHead->pNext = pCur;
		pPre->pNext = pNext;
		pCur = pNext;

	}
}
  • 代码执行示意图

链表划分
  • 给定一个链表和一个值x,将链表划分成两 部分,使得划分后小于x的结点在前,大于 等于x的结点在后。在这两部分中要保持原 链表中的出现顺序。

    • 如:给定链表1→4→3→2→5→2和x = 3,返回 1→2→2→4→3→5
  • 问题分析

    • 分别申请两个指针p1和p2,小于x的添加到 p1中,大于等于x的添加到p2中;最后,将 p2链接到p1的末端即可。
    • 时间复杂度是O(N),空间复杂度为O(1);该 问题其实说明:快速排序对于单链表存储结 构仍然适用。
      • 注:不是所有排序都方便使用链表存储,如堆 排序,将不断的查找数组的n/2和n的位置,用链 表做存储结构会不太方便。
ypedef struct tagSNode{
	int value;
	tagSnode *pNext;

	tagSNode(int v):value(v),pNext(NULL){}
}SNode;

int _tmain(int argc,_TCHAR* argv[]){
	SNode* pHead = new SNode(0);
	pHead->pNext = NULL;//这一步冗余
	for (int i = 0; i < 10; ++i)
	{
		SNode *p = new SNode(rand() % 100);
		p->pNext = pHead->pNext;
		pHead->pNext = p;
	}
	Print(pHead);
	Partition(pHead,50);
	Print(pHead);
	Destory(pHead);
	return 0;
}

void Destory(SNode* p){
	SNode *next;
	while(p){
		next = p->next;
		delete p;
		p = next;
	}
}
void Partition(SNode* pHead,int pivotKey){
	//两个链表的头指针
	SNode* pLeftHead = new SNode(0);
	SNode* pRightHead = new SNode(0);

	//两个链表的当前最后一个元素
	SNode* left = pLeftHead;
	SNode* right = pRightHead;
	SNode* p = pHead->pNext;
	while(p){//遍历原链表
		if(p->value < pivotKey){
			left->pNext = p;
			left = p;
		}else{
			right->pNext = p;
			right = p;
		}
		p = p->pNext;
	}
	//将right链接到left尾部
	left->pNext = pLeftHead->pNext;

	delete pLeftHead;
	delete pRightHead;
}
排序链表中去重
  • 给定排序的链表,删除重复元素,只保留重 复元素第一次出现的结点。
  • 如:
    • 给定:2→3→3→5→7→8→8→8→9→9→10
    • 返回:2→3→5→7→8→9→10
  • 问题分析
    • 若p->next的值和p的值相等,则将p->next>next赋值给p,删除p->next;重复上述过 程,直至链表尾端。
typedef struct tagSNode{
	int value;
	tagSnode *pNext;

	tagSNode(int v):value(v),pNext(NULL){}
}SNode;

int _tmain(int argc,_TCHAR* argv[]){
	SNode* pHead = new SNode(0);
	int data[] = [2,3,3,5,7,8,8,8,9,20,20];
	int size = sizeof(data)/sizeof(int);
	for (int i = size -1; i >=0; i--)
	{
		SNode* p = new SNode(data[i]);
		p->pNext = pHead->pNext;
		pHead->pNext = p;
	}
	Print(pHead);
	DeleteDuplicateNode(pHead);
	Print(pHead);
	Destroy(pHead);
	return 0;
}
//方法一 2,3,3 pPre=3 pNext = 3
void DeleteDuplicateNode(SNode* pHead){
	SNode* pPre = pHead->pNext;
	SNode* pCur;
	while(pPre){
		pCur = pPre->pNext;
		if(pCur &&(pCur->value == pPre->value)){
			pPre->pNext = pCur->pNext;
			delete pCur;
		}else{
			pPre = pCur;
		}
	}
}
//方法二 2,3,3 pPre=2 pCur = 3 pNext = 3
void DeleteDuplicateNode2(SNode *pHead){
	SNode* pPre = pHead;
	SNode* pCur = pPre->pNext;
	SNode* pNext;
	while(pCur){
		pNext = pCur->pNext;
		while(pNext && (pCur->value == pNext->value)){
			pPre->pNext = pNext;
			delete pCur;
			pCur = pNext;
			pNext = pCur->pNext;
		}
		pPre = pCur;
		pCur = pNext;
	}
}
排序链表中去重2
  • 若题目变成:若发现重复元素,则重复元素 全部删除,代码应该怎么实现呢?
  • 如:
  • 给定:2→3→3→5→7→8→8→8→9→9→10
    • 返回:2→5→7→10
void DeleteDuplicateNode3(SNode *pHead){
	SNode* pPre = pHead;
	SNode* pCur = pPre->pNext;
	SNode* pNext;
	bool bDup;
	while(pCur){
		pNext = pCur->pNext;
		bDup = false;
		while(pNext && (pCur->value == pNext->value)){
			pPre->pNext = pNext;
			delete pCur;
			pCur = pNext;
			pNext = pCur->pNext;
			bDup = true;
		}
		if(bDup){//此刻的pCur与元数据重复,删之
				pPre->pNext = pNext;
				delete pCur;
		}else{//pCur未发现重发,则pPre后移
			pPre = pCur;
		}
		pCur = pNext;
	}
}

更多内容请关注微信公众号:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值