链表相加
- 给定两个链表,分别表示两个非负整数。它 们的数字逆序存储在链表中,且每个结点只 存储一个数字,计算两个数的和,并且返回 和的链表头指针
- 如:输入: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;
}
}
更多内容请关注微信公众号: