在无表头单链表中删除指定值 x 的结点
循环遍历的实现方法如下:
template<typename T>
class WorkList : public LinkList<T>
{
protected:
typedef typename LinkList<T>::Node Node;
/* 删除链表中的重复结点 */
void rmdup(Node* head)
{
if(head != nullptr)
{
rmdup(head->next); // 删除除去当前结点的子链表中的重复结点
rmdup(head->next, head->value); // 通过当前结点删除子链表中存在与当前结点值相同的结点
}
}
/* head 链表的第一个结点,通过 val 删除相同值的结点 */
void rmdup(Node*& head, int val) // head 为引用是因为这个链表是不带头结点的链表,head 可能需要指向其他的结点
{
Node* pre = nullptr; // pre 指向待删除结点的前一个结点
Node* slider = head; // slider 用于遍历链表
while(slider)
{
/* 需要删除 slider 指向的结点 */
if(slider->value == val)
{
/* 当要删除的结点为链表的第一个结点时 */
if(slider == head)
{
head = slider->next; // 将 head 后移一个结点
delete slider;
slider = head; // slider 重新指向链表的第一个结点
}
else
{
Node* toDel = slider;
pre->next = toDel->next;
slider = toDel->next;
delete toDel;
}
}
else
{
pre = slider;
slider = slider->next;
}
}
}
public:
void rmdup()
{
rmdup(this->m_header.next);
}
};
递归方法的实现如下:
template<typename T>
class WorkList : public LinkList<T>
{
protected:
typedef typename LinkList<T>::Node Node;
/* 删除链表中的重复结点 */
void rmdup(Node* head)
{
if(head != nullptr)
{
rmdup(head->next); // 删除除去当前结点的子链表中的重复结点
rmdup(head->next, head->value); // 通过当前结点删除子链表中存在与当前结点值相同的结点
}
}
/* head 链表的第一个结点,通过 val 删除相同值的结点 */
void rmdup(Node*& head, int val) // head 为引用是因为这个链表是不带头结点的链表,head 可能需要指向其他的结点
{
if(head)
{
if(head->value == val)
{
Node* toDel = head;
head = head->next;
delete toDel;
rmdup(head, val);
}
else
{
rmdup(head->next, val);
}
}
}
public:
void rmdup()
{
rmdup(this->m_header.next);
}
};
参数 head 为什么是引用?
因为此链表是不带头结点的,所以可能需要改变 head 的指向,而 head 并非全局变量和成员变量,所以需要加上引用。
如果不使用引用参数,rmdup() 函数原型该如何设计?
rmdup() 返回删除指定值后的第一个链表结点。
计算 n 个整型数的平均值
/* 常规做法,容易造成数据溢出 */
int toAverageClassic(int a[], int n)
{
int ret = 0;
if(n > 0)
{
for(int i = 0; i < n; i++)
{
ret += a[i];
}
ret /= n;
}
return ret;
}
/* 改进做法,有效的避免数据溢出 */
int toAverage(int a[], int n)
{
int ret = 0;
if(n > 0)
{
int m = 0;
for(int i = 0; i < n; i++)
{
ret += a[i] / n;
/* 求平均值的补偿部分, 这样做补偿部分不会溢出 */
m += a[i] % n;
ret += m / n;
m %= n;
}
}
return ret;
}