您的位置:首页 > 其它

分支界定法:最大装载问题,获得最优路径(使用FIFO),深刻学习指针的引用的本质

2012-02-11 08:44 337 查看
// 17x4.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

// 分支界定法:最大装载问题,获得最优路径(使用FIFO),深刻学习指针的引用的本质

#include <iostream.h>
#include "lqueue.h"
#include "qnode.h"     // QNode具有一个QNode *parent, bool LChild, T weight三个属性

// 如果不是叶节点,就加入到Q队列里。新节点是E的孩子。
// E与bestE有区别,一个不带引用,一个带引用,深刻体会QNode<T>*& bestE的使用
template<class T>
void AddLiveNode(LinkedQueue<QNode<T>*>& Q, T wt, int i, int n, T bestw,
QNode<T> *E, QNode<T>*& bestE, int bestx[], bool ch)
{
cout << "函数参数QNode<T>*& bestE去掉&,&bestE的地址就变了=" << &bestE << ",  bestE="<< bestE << endl;

// bestE被不断传进来,传递方式是带引用的指针QNode<T>*& ,所以实际上只有一个,以后就靠它回溯取得最优路径
// 叶节点不需要生成,只要到达了叶节点并且是最大值的那一次,直接记录下bestx
= ch;,即0或者1
// 于是只要记录叶节点的parent就可以了,即bestE,它已经在GetMaxLoading里定义,并且是唯一的。然后靠它回溯取得最优路径
// 不是叶节点就也有可能有最大值。但不是叶节点就不必更新bestE和bestx
的值(bestx
=true/false都有可能)
if (i == n) { // 到达叶节点
if (wt == bestw) {
bestE = E; // 迄今的最佳值,而且只在这里有可能被改变。
cout << "adr changed???    &bestE=" << &bestE << ",  bestE="<< bestE << endl;
bestx
= ch;
cout << "i=" << i << ",  best adr node="<< bestE << endl;
}
return;
}

// 只要不是叶子,添加到队列,这样方便由最后记录的那个叶节点来回溯,得到最佳路径
QNode<T> *b;   // 每次都新建一个节点,所以多生成了许多QNode节点
b = new QNode<T>;
b->weight = wt; // 节点的重量等于路径到当前节点的值
b->parent = E;  //
b->LChild = ch; //
cout << "i=" << i << ", E="<< E << ",  adr node="<< b << endl;

// 这里队列Q添加的元素比较特殊,具有parent和LChild属性,而以前只是wt的值
Q.Add(b);
}

// 返回最大装载和最大装载的路径
template<class T>
T GetMaxLoading(T w[], T c, int n, int bestx[])
{
LinkedQueue<QNode<T>*> Q;  // 活结点队列
// 为第一层初始化
Q.Add(0);          // 0 变成了层结束的标志
int i = 1;         // E-节点的层
T Ew = 0,          // E-节点的权重(节点自身与所有祖先的权重的累加)
bestw = 0;       // 迄今最佳重量
T r = 0;           // E-节点时候的所有物品的剩余重量总和
for (int j = 2; j <= n; j++)
r += w[i];
// QNode具有一个QNode *parent, bool LChild, T weight三个属性
QNode<T> *E = 0,   // 当前E-节点,作为AddLiveNode的参数,作为当前节点的parent。因此首节点的parent为0
*bestE;   //迄今最佳E-节点,作为AddLiveNode的参数

   /*
   4G的内存地址, 系统还要留下一半($80000000 - $FFFFFFFF, 这 2G 是各进程共享的)用作宏观管理;
   只给程序 2G(0 - $7FFFFFFF). 就这 2G 的地址, 也不是全给用户的, 低端的 0 - $FFFF 是用于空指针分配, 禁止访问;
   高端的 $7FFF0000 - $7FFFFFFF 也留出来作为进程的临界区, 也禁止访问.
   其实进程的私有空间地址只有 $10000 - $7FFEFFFF.
   */

// 故意打印没有经过初始化的指针:
cout << "&bestE=" << &bestE << ",  bestE="<< bestE << endl;
// 体会指针的引用:&bestE=0x0012FEAC,  bestE=0xCCCCCCCC
// 这里证明:1)没有初始化的时候,指针自身的地址是落在用户内存区(0x0012FEAC),指向的地址却是落在系统内存区的(0xCCCCCCCC),所以此时不能使用(*pointer),因为这是禁止访问的区域。
// 2)程序运行时生成的QNode地址全部落在用户内存区
// 3)函数使用带有&的参数QNode<T>*& bestE,使得&bestE永远等于0x0012FEAC,变的仅仅是bestE的值(指针指向的地方)。函数使用不带&的话,函数内部的&bestE将是另外一个值0x0012FE44,

while (true) {
// 测试左孩子
T wt = Ew + w[i];
if (wt <= c) { // 可行的左孩子
if (wt > bestw) bestw = wt; // 这里已经更新了bestw了,所以记录最佳路径的时候,它们只要相等就代表是最佳路径了
// 左右孩子的E是AddLiveNode里即将生成的QNode的parent,所以左右的节点都有parent
AddLiveNode(Q, wt, i, n, bestw, E, bestE, bestx, true); // 左孩子true,代表1
}
// 测试右孩子
if (Ew + r > bestw)
AddLiveNode(Q, Ew, i, n, bestw, E, bestE, bestx, false); // 右孩子false,代表0

// 左右孩子都检测过了,就要删除当前节点。并且把下一个节点取出放到E里
// E是记录路径的关键
Q.Delete(E);
if (!E) { // 除了层结束标志,其它wt都不会等于0
if (Q.IsEmpty()) break; // 找到最优解后跳出循环,准备构建路径
Q.Add(0);     // 层结束的标志
Q.Delete(E);
i++;
r -= w[i];
}
// 取出新E-节点的重量,准备下一个循环进行比较
Ew = E->weight;
}

// 进行了n-1遍循环(这里是4遍循环),除了叶节点直接已经记录下之外,剩下的路径靠它进行回溯取得
for (j=n-1; j>0; j--) {
bestx[j] = bestE->LChild; // 判断是取左孩子路径还是右孩子路径
bestE = bestE->parent; // 最佳路径由最新的bestE决定,然后沿着parent向上回溯构建
}

return bestw;
}

void main(void)
{
int w[6] = {0, 2, 2, 6, 5, 5};
int x[6];
int n = 5;
int c = 16;
cout << "Max loading is " << GetMaxLoading(w,c,n,x) << endl;
cout << "Loading vector is" << endl;
for (int i = 1; i <= n; i++)
cout << x[i] << ' ';
cout << endl;
}

// ------------------qnode.h文件---------------------------
// used by bbloadc.cpp

#ifndef QNode_
#define QNode_

template<class T>
class  QNode {
friend void AddLiveNode(LinkedQueue<QNode<T>*> &, T, int, int, T, QNode<T> *, QNode<T> *&, int *, bool);
friend T GetMaxLoading(T *, T, int, int *);
private:
QNode *parent; // pointer to parent node
bool LChild;   // true iff left child of parent
T weight;      // weight of partial solution
// defined by path to this node
};

#endif

// ------------------lqueue.h文件---------------------------

// header file lqueue.h
// linked queue

#ifndef LinkedQueue_
#define LinkedQueue_
#include "node.h"
#include "xcept.h"

template<class T>
class LinkedQueue {
// FIFO objects
public:
LinkedQueue() {front = rear = 0;} // constructor
~LinkedQueue(); // destructor
bool IsEmpty() const
{return ((front) ? false : true);}
bool IsFull() const;
T First() const; // return first element
T Last() const; // return last element
LinkedQueue<T>& Add(const T& x);
LinkedQueue<T>& Delete(T& x);
private:
Node<T> *front;  // pointer to first node
Node<T> *rear;   // pointer to last node
};

template<class T>
LinkedQueue<T>::~LinkedQueue()
{// Queue destructor.  Delete all nodes.
Node<T> *next;
while (front) {
next = front->link;
delete front;
front = next;
}
}

template<class T>
bool LinkedQueue<T>::IsFull() const
{// Is the queue full?
Node<T> *p;
try {p = new Node<T>;
delete p;
return false;}
catch (NoMem) {return true;}
}

template<class T>
T LinkedQueue<T>::First() const
{// Return first element of queue.  Throw
// OutOfBounds exception if the queue is empty.
if (IsEmpty()) throw OutOfBounds();
return front->data;
}

template<class T>
T LinkedQueue<T>::Last() const
{// Return last element of queue.  Throw
// OutOfBounds exception if the queue is empty.
if (IsEmpty()) throw OutOfBounds();
return rear->data;
}

template<class T>
LinkedQueue<T>& LinkedQueue<T>::Add(const T& x)
{// Add x to rear of queue.  Do not catch
// possible NoMem exception thrown by new.

// create node for new element
Node<T> *p = new Node<T>;
p->data = x;
p->link = 0;

// add new node to rear of queue
if (front) rear->link = p;  // queue not empty
else front = p;             // queue empty
rear = p;

return *this;
}

template<class T>
LinkedQueue<T>& LinkedQueue<T>::Delete(T& x)
{// Delete first element and put it in x.  Throw
// OutOfBounds exception if the queue is empty.

if (IsEmpty()) throw OutOfBounds();

// save element in first node
x = front->data;
//  cout << "        x=" << x << endl;

// delete first node
Node<T> *p = front;
front = front->link;
delete p;

return *this;
}

#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐