Leetcode 第二章线性表--2.2 单链表--2.2.1 add two numbers--2017/7/25

单链表如下:

// 单链表节点
struct ListNode {     //结构体
int val;    //数据成员
ListNode *next;  //链域
ListNode(int x) : val(x), next(nullptr) { }  //初始化构造方法
};

数据结构、算法与应用C++语言描述 P113

问题描述:

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8

分析:342+465=807,都是倒序的。


问题一:

为了解决这种二义性,C++11标准引入了关键字nullptr,它作为一种空指针常量。


问题二:C++ ?表达式

三元运算符(?:)(问号冒号)

三元运算符(?:),也称条件运算符,是if...else结构的简化形式。其名称的出处是它带有三个操作数。它可以计算一个条件,如果为真,就返回一个值;如果条件为假,则返回另一个值。其语法如下:

condition?true_value:false_value


问题三:C++初始化单链表

#include <iostream> 
using namespace std;


typedef struct _node     //类型别名Node
{
char data;    //数据域,这里是char类型注意了
struct _node *next;  //链域
}Node;


class List        //单项链表类
{
public:
List();
~List();
bool Append(char data);//在单链表尾部插入元素 
bool InsertAt(int index, char data);//在单链表指定位置插入元素 
bool DeleteAt(int index); //删除单链表指定位置元素 
bool IsEmpty();//判断单链表是否为空 
bool Output();//输出整个单链表 
bool OutputAt(int index);//输出链表指定位置元素 
bool OutputPos(char data);//输出链表元素位置 
int GetLength();// 获取单链表长度 
private:
Node* m_pHead; // 单链表头指针 
int m_length; // 单链表长度,添加,删除的时候进行更新 
};


List::List()
{
m_pHead = nullptr;  //默认构造头指针为空,注意了Node* m_pHead,是一个地址
m_length = 0;      //长度为0
}


List::~List()      //析构函数
{
Node* pNode = m_pHead;
while (pNode)
{
m_pHead = pNode->next;
free(pNode);
pNode = m_pHead;
}
}


bool List::IsEmpty()    //判断是否为空
{
return m_length == 0 ? true : false;
}


int List::GetLength()   //获取单链表长度
{
return m_length;
}


bool List::Append(char data)   //在单链表尾部插入元素 
{
Node* pNewNode = new Node;    //分配局部变量


if (pNewNode == nullptr)
{
return false;
}
else{
pNewNode->data = data;
pNewNode->next = nullptr;
}


if (m_pHead == nullptr)
{
m_pHead = pNewNode;   //头指针指向pNewNode
m_length = 1;     //长度也变化
}
else{
Node* pNode = m_pHead;  //新的局部变量pNode
while (pNode->next) //遍历单链表,判断是否下一个节点为空 
{
pNode = pNode->next;
}
pNode->next = pNewNode;//将新节点插入尾部 
m_length++; //更新单链表长度 
}
return true;
}

bool List::InsertAt(int index, char data)
{
if (index >= m_length && index <= 0)
return false;
if (m_pHead == NULL)
return false;
Node* pNode = m_pHead;
int count = 1;
while (pNode)
{
pNode = pNode->next;
count++;
if (count == index - 1) // 在插入节点的前一个节点处停止遍历 
break;
}


// 分配新节点 
Node* pNewNode = new Node;
if (pNewNode == NULL)
{   // 分配新节点失败,返回 
return false;
}
else{ //初始化新节点内容 
pNewNode->data = data;
pNewNode->next = NULL;
}


// 保存下一个节点的指针 
Node* pNextNode = pNode->next;
// 将当前节点指向新节点 
pNode->next = pNewNode;
// 将新节点指向下一个节点 
pNewNode->next = pNextNode;
return true;
}


bool List::DeleteAt(int index)
{
//极端情况判断 
if (m_pHead == NULL)
return false;
if (index > m_length && index <= 0)
return false;
Node* pNode = m_pHead;
int count = 1;


while (pNode->next)
{
//依次走访单链表,在欲删除节点的前一个节点处停止遍历 
if (count == index - 1)
break;
pNode = pNode->next;
count++;
}


// 将要删除的节点的下一个节点的指针保存起来,pNode节点现在是要删除节点的前一个节点 
Node* pNextNode = pNode->next->next;
free(pNode->next);
m_length--;
pNode->next = pNextNode;
return true;
}


bool List::OutputPos(char data)
{
Node* pNode = m_pHead;
int count = 1;
while (pNode->next)
{
if (data == pNode->data)
break;
pNode = pNode->next;
count++;
}


if (count > m_length)
return false;
cout << "元素" << data << "的位置: " << count << endl;
return true;
}


bool List::OutputAt(int index)
{
if (m_pHead == NULL)
return false;
if (index > m_length && index <= 0)
return false;
Node* pNode = m_pHead;
int count = 1;
while (pNode->next)
{
if (count == index)
break;
pNode = pNode->next;
count++;
}
cout << "第" << index << "个元素: " << pNode->data << endl;
return true;
}


bool List::Output()
{
if (m_pHead == NULL)
return false;
Node* pNode = m_pHead;
int count = 1;
while (pNode)
{
cout << "第" << count << "个元素:" << pNode->data << endl;
pNode = pNode->next;
count++;
}
return true;
}

int main()
{
cout << "(1) 初始化单链表H" << endl;
List list;
cout << "单链表初始化完毕!" << endl;
cout << "\n(2) 依次采用尾插法插入 a,b,c,d,e元素" << endl;
list.Append('a');
list.Append('b');
list.Append('c');
list.Append('d');
list.Append('e');
cout << "\n(3) 输出单链表H" << endl;
list.Output();
cout << "\n(4) 输出单链表H长度" << endl;
cout << "单链表长度: " << list.GetLength() << endl;
cout << "\n(5) 判断单链表H是否为空" << endl;
if (list.IsEmpty())
cout << "单链表为空! " << endl;
cout << "单链表不为空! " << endl;
cout << "\n(6) 输出单链表H的第三个元素" << endl;
list.OutputAt(3);
cout << "\n(7) 输出元素'a'的位置" << endl;
list.OutputPos('a');
cout << "\n(8) 在第四元素位置上插入'f'元素" << endl;
list.InsertAt(4, 'f');
cout << "\n(9) 输出单链表H" << endl;
list.Output();
cout << "\n(10) 删除单链表H的第三个元素" << endl;
list.DeleteAt(3);
cout << "\n(11) 输出单链表H" << endl;
list.Output();
return 0;
}


答案及测试代码


#include <iostream>
using namespace std;

//LeetCode, Add Two Numbers
//时间复杂度O(m+n),空间复杂度O(1)

struct ListNode   //结构
{
int val; //数据域
ListNode *next;  //链域
ListNode(int x) :val(x), next(nullptr){}
};

//下面要定义一个chain类实现单链表,"头指针"指向链表的开始,而最后一个节点的指针域为nullptr
class chain{
public:
chain();    //构造函数
~chain();    //析构函数
void Append(int data);//在单链表尾部插入元素
void Output();//输出整个单链表
ListNode* m_pHead; // 单链表头指针 
int m_length; // 单链表长度,添加,删除的时候进行更新 
};

chain::chain()  //构造函数实现
{
m_pHead = nullptr;  //默认构造头指针为空,注意了node* m_phead,是一个地址
m_length = 0;      //长度为0
}

chain::~chain()      //析构函数
{
ListNode* pNode = m_pHead;   //局部变量
while (pNode)     //pNode是地址,不是链域值
{
m_pHead = pNode->next;
free(pNode);
pNode = m_pHead;
}
}

void chain::Append(int data)   //在单链表尾部插入元素 
{
ListNode* pNewNode = new ListNode(data);    //分配局部变量


if (m_pHead == nullptr)
{
m_pHead = pNewNode;   //头指针指向pNewNode
m_length = 1;     //长度也变化
}
else{
ListNode* pNode = m_pHead;  //新的局部变量pNode
while (pNode->next) //遍历单链表,判断是否下一个节点为空 
{
pNode = pNode->next;
}
pNode->next = pNewNode;//将新节点插入尾部 
m_length++; //更新单链表长度 
}
}

void chain::Output()
{
ListNode* pNode = m_pHead;  //局部变量
int count = 1;
while (pNode)
{
cout << "第" << count << "个元素:" << pNode->val << endl;
pNode = pNode->next;
count++;
}
}

class Solution{
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2){  //输入是指针,返回亦是指针
ListNode dummy(-1);  //dummy节点,头节点,可以说没有用的
int carry = 0;   //进位,初始化为0
ListNode *prev = &dummy;  //把它的地址给prev  注意下面的|| 是或运算  然后那个?:运算就很精妙
for (ListNode *pa = l1, *pb = l2; pa != nullptr || pb != nullptr;
pa = pa == nullptr ? nullptr : pa->next, pb = pb == nullptr ? nullptr : pb->next,
prev = prev->next){
const int ai = pa == nullptr ? 0 : pa->val;
const int bi = pb == nullptr ? 0 : pb->val;
const int value = (ai + bi + carry) % 10;     //余数,注意这里加了进位carry
carry = (ai + bi + carry) / 10; //商--进位
prev->next = new ListNode(value); //尾插法
}
if (carry > 0)   //如果最后两位相加,还有进位,就再增加一个节点
prev->next = new ListNode(carry);
return dummy.next;  //dummy.next是有意义的输出的开始!!!!
}
};


int main(){
chain A;
chain B;
chain C;   //结果
cout << "A:" << endl;
A.Append(2);
A.Append(4);
A.Append(3);
A.Output();
cout << "B:" << endl;
B.Append(5);
B.Append(6);
B.Append(4);
B.Output();


Solution mySolution;
C.m_pHead = mySolution.addTwoNumbers(A.m_pHead,B.m_pHead);
cout << "C:" << endl;
C.Output();

return 0;
}

Leetcode 第二章线性表--2.2 单链表--2.2.1 add two numbers--2017/7/25


总结:这就是一个两数相加的问题,只不过在单向链表的这个背景下。