读书笔记之:数据结构,算法与应用(2)

第5章 堆栈
堆栈是一个后进先出(last-in-first-out, LIFO)的数据结构。
1. 数组实现的堆栈
源代码如下:
View Code
#include <iostream>
using namespace std;
template<class T>
class Stack{
    public:
        Stack(int MaxStackSize=10);
        ~Stack(){
            delete [] stack;
        }
        bool IsEmpty()const{
            return top==-1;
        }
        bool IsFull()const{
            return top==MaxTop;
        }
        T Top()const;
        Stack<T>& Add(const T& x);
        Stack<T>& Delete(T & x);
    private:
        int top;
        int MaxTop;
        T* stack;
};
template<class T>
Stack<T>::Stack(int MaxStackSize)
{
    MaxTop=MaxStackSize-1;
    stack=new T[MaxStackSize];
    top=-1;
}
template<class T>
T Stack<T>::Top()const
{
    if(IsEmpty())
        throw "Out of Bounds";
    return stack[top];
}
template<class T>
Stack<T>& Stack<T>::Add(const T& x)
{
    if(IsFull())
        throw "Not enough Memorry";
    stack[++top]=x;
cout<<"Success"<<endl;
    return *this;
}
template<class T>
Stack<T>& Stack<T>::Delete(T & x)
{
    if(IsEmpty())
        throw "Out of Bounds";
    x=stack[top--];
    return *this;
}
int main(void)                                       
{
    int x;
    Stack<int> S(3);
    try {
        S.Add(1).Add(2).Add(3).Add(4);
    }
    catch (...) {
        cout << "Could not complete additions" << endl;
    }
    cout << "Stack should be 123" << endl;
    cout << "Stack top is " << S.Top() << endl;
    try {
        S.Delete(x);
        cout << "Deleted " << x << endl;
        S.Delete(x);
        cout << "Deleted " << x << endl;
        S.Delete(x);
        cout << "Deleted " << x << endl;
        S.Delete(x);
        cout << "Deleted " << x << endl;
    }
    catch (...) {
        cout << "Last delete failed " << endl;
    }
}
                                                      
2.链表实现的堆栈
源代码如下:
View Code
#include <iostream>
using namespace std;
template<class T>
class LinkedStack;
template<class T>
class Node{
    friend class LinkedStack<T>;
    private:
    T data;
    Node<T>* link;
};
template<class T>
class LinkedStack{
    public:
        LinkedStack(){
            top=0;
        }
        ~LinkedStack();
        bool IsEmpty()const{
            return top==0;
        }
        bool IsFull()const;
        T Top()const;
        LinkedStack<T>& Add(const T& x);
        LinkedStack<T>& Delete(T& x);
    private:
        Node<T>*top;
};
template<class T>
LinkedStack<T>::~LinkedStack()
{
    Node<T>*next;
    while(top){
        next=top->link;
        delete top;
        top=next;
    }
}
template<class T>
bool LinkedStack<T>::IsFull()const
{
    try{
        Node<T> *p=new Node<T>;
        delete p;
        return false;
    }
    catch(...){
        return true;
    }
}
template<class T>
T LinkedStack<T>::Top()const
{
    if(IsEmpty())
        throw "OutofBounds";
    return top->data;
}
    template<class T>
LinkedStack<T>& LinkedStack<T>::Add(const T& x)
{
    Node<T> *p=new Node<T>;
    p->data=x;
    p->link=top;
    top=p;
    return *this;
}
    template<class T>
LinkedStack<T>& LinkedStack<T>::Delete(T& x)
{
    if(IsEmpty())
        throw "Out of Bounds()";
    x=top->data;
    Node<T> *p;
    p=top->link;
    delete top;
    top=p;
    return *this;
}
int main(void)
{
    int x;
    LinkedStack<int> S;
    try {S.Add(1).Add(2).Add(3).Add(4);}
    catch (...) {
        cout << "Could not complete additions" << endl;
    }
    cout << "Stack should be 1234" << endl;
    cout << "Stack top is " << S.Top() << endl;
    try {
        S.Delete(x);
        cout << "Deleted " << x << endl;
        S.Delete(x);
        cout << "Deleted " << x << endl;
        S.Delete(x);
        cout << "Deleted " << x << endl;
        S.Delete(x);
        cout << "Deleted " << x << endl;
    }
    catch (...) {
        cout << "Last delete failed " << endl;
    }
}
3. 堆栈使用
(1)括号匹配
View Code
#include <iostream>
#include <stack>
#include <string>
using namespace std;
void PrintMatchedPairs(string expr){
    stack<int> s;
    string::iterator it;
    int i=1;
    for(it=expr.begin();it!=expr.end();++it,++i){
        if(*it=='(')
            s.push(i);
        else if(*it==')')
        {
            if(s.empty()){
                cout<<"No match for left parentthesis at "<<i<<endl;

            }
            else{
                int t=s.top();
                cout<<t<<" "<<i<<endl;
                s.pop();
            }
        }
    }
    while(!s.empty()) {
        int t=s.top();
        cout<<"No match for left parentthesis at "<<t<<endl;
        s.pop();
    }
}
int main(void)                                          
{
    const int MaxLength=200;
    char expr[MaxLength];
    cout << "Type an expression of length at most "
        << MaxLength << endl;
    cin.getline(expr, MaxLength);
    cout <<"The pairs of matching parentheses in"
        << endl;
    cout<<expr<<endl;
    cout <<"are" << endl;
    string expr2(expr);
    PrintMatchedPairs(expr2);
}
(2)汉诺塔
View Code
#include <iostream>
#include <stack>
using namespace std;
void TowersofHanoi(int n,int x,int y,int z){
    if(n>0){
        TowersofHanoi(n-1,x,z,y);
        cout<<"move top disk from tower "<<x<<" to top of tower "<<y<<endl;
        TowersofHanoi(n-1,z,y,x);
    }
}
int main(){
 cout << "Moves for a three disk problem are" << endl;
  TowersofHanoi(3,1,2,3);

}

网上给出的一个很不错的非递归方式的汉诺塔实现,具体见这,下面是代码:

View Code
#include <iostream>
using namespace std; 

//圆盘的个数最多为64 
const int MAX = 64

//用来表示每根柱子的信息
struct st{
    int s[MAX]; //柱子上的圆盘存储情况
    int top; //栈顶,用来最上面的圆盘
    char name; //柱子的名字,可以是A,B,C中的一个
    int Top()//取栈顶元素
    {
        return s[top];
    }
    int Pop()//出栈
    {
        return s[top--];
    }
    void Push(int x)//入栈
    {
        s[++top] = x;
    }
} ; 

long Pow(int x, int y); //计算x^y
void Creat(st ta[], int n); //给结构数组设置初值
void Hannuota(st ta[], long max); //移动汉诺塔的主要函数 

int main(void)
{
    int n;
    cin >> n; //输入圆盘的个数
    st ta[3]; //三根柱子的信息用结构数组存储
    Creat(ta, n); //给结构数组设置初值 

    long max = Pow(2, n) - 1;//动的次数应等于2^n - 1
    Hannuota(ta, max);//移动汉诺塔的主要函数 

    return 0;


void Creat(st ta[], int n)
{
    ta[0].name = 'A';
    ta[0].top = n-1;
    //把所有的圆盘按从大到小的顺序放在柱子A上
    for (int i=0; i<n; i++)
        ta[0].s[i] = n - i;
    //柱子B,C上开始没有没有圆盘
    ta[1].top = ta[2].top = 0;
    for (int i=0; i<n; i++)
        ta[1].s[i] = ta[2].s[i] = 0;
    //若n为偶数,按顺时针方向依次摆放 A B C
    if (n%2 == 0)
    {
        ta[1].name = 'B';
        ta[2].name = 'C';
    }
    else  //若n为奇数,按顺时针方向依次摆放 A C B
    {
        ta[1].name = 'C';
        ta[2].name = 'B';
    }


long Pow(int x, int y)
{
    long sum = 1;
    for (int i=0; i<y; i++)
        sum *= x; 

    return sum;


void Hannuota(st ta[], long max)
{
    int k = 0//累计移动的次数
    int i = 0;
    int ch;
    while (k < max)
    {
        //按顺时针方向把圆盘1从现在的柱子移动到下一根柱子
        ch = ta[i%3].Pop();
        ta[(i+1)%3].Push(ch);
        cout << ++k << "" <<
            "Move disk " << ch << " from " << ta[i%3].name <<
            " to " << ta[(i+1)%3].name << endl;
        i++;
        //把另外两根柱子上可以移动的圆盘移动到新的柱子上
        if (k < max)
        {     

            //把非空柱子上的圆盘移动到空柱子上,当两根柱子都为空时,移动较小的圆盘
            if (ta[(i+1)%3].Top() == 0 ||
                    ta[(i-1)%3].Top() > 0 &&
                    ta[(i+1)%3].Top() > ta[(i-1)%3].Top())
            {
                ch =  ta[(i-1)%3].Pop();
                ta[(i+1)%3].Push(ch);
                cout << ++k << "" << "Move disk "
                    << ch << " from " << ta[(i-1)%3].name
                    << " to " << ta[(i+1)%3].name << endl;
            }
            else
            {
                ch =  ta[(i+1)%3].Pop();
                ta[(i-1)%3].Push(ch);
                cout << ++k << "" << "Move disk "
                    << ch << " from " << ta[(i+1)%3].name
                    << " to " << ta[(i-1)%3].name << endl;
            }
        }
    }

本人使用STL中的stack对上面的代码进行了一下修改:

View Code
class Tower{
    public:
        stack<int> st;
        char name;
};
int Pow(int x,int y){
    int sum=1;
    for(int i=0;i<y;i++)
        sum*=x;
    return sum;
}
void Hanoi(int N){
    Tower ta[3];
    ta[0].name='A';
    for(int i=0;i<N;i++)
        ta[0].st.push(N-i);
    if(N%2==0){
        ta[1].name='B';
        ta[2].name='C';
    }
    else{
        ta[1].name='C';
        ta[2].name='B';
    }
    int k=0;
    int i=0;
    int ch;
    int max=Pow(2,N)-1;
    while(k<max){
        ch=ta[i%3].st.top();
        ta[i%3].st.pop();
        ta[(i+1)%3].st.push(ch);
        cout<<++k<<": Move disk "<<ch<<" from "<<ta[i%3].name<<" to "<<ta[(i+1)%3].name<<endl;
        i++;
        if(k<max){
            if(ta[(i+1)%3].st.empty()||!ta[(i-1)%3].st.empty()&&ta[(i+1)%3].st.top()>ta[(i-1)%3].st.top()){
                ch=ta[(i-1)%3].st.top();
                ta[(i-1)%3].st.pop();
                ta[(i+1)%3].st.push(ch);
                cout<<++k<<": Move disk "<<ch<<" from "<<ta[(i-1)%3].name<<" to "<<ta[(i+1)%3].name<<endl;
            }
            else{
                ch=ta[(i+1)%3].st.top();
                ta[(i+1)%3].st.pop();
                ta[(i-1)%3].st.push(ch);
                cout<<++k<<": Move disk "<<ch<<" from "<<ta[(i+1)%3].name<<" to "<<ta[(i-1)%3].name<<endl;
            }
        }
    }
}

下图是对两种方法(递归和迭代)的比较:

 

上图给出的是4个盘的情况,对比可以发现,两种方法移动盘的步骤是一样的。

 

(3)火车车厢重排

View Code
//using stack
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
bool Hold(int c,int &minH,int& minS,vector<stack<int> >& H,int k,int n){
    int BestTrack=0,BestTop=n+1,x;
    for(int i=1;i<=k;i++){
        if(!H[i].empty()){
            x=H[i].top();
            if(c<x&&x<BestTop){
                BestTop=x;
                BestTrack=i;
            }
        }
        else{
            if(!BestTrack)
                BestTrack=i;
        }
    }
    if(!BestTrack)
        return false;
    H[BestTrack].push(c);
    cout<<"Move car "<<c<<" from input to holding track "<<BestTrack<<endl;
    if(c<minH) {
        minH=c;
        minS=BestTrack;
    }
    return true;
}
void Output(int& minH,int& minS,vector<stack<int> >& H,int k,int n){
    int c;
    c=H[minS].top();
    H[minS].pop();
    cout<<"Move car "<<minH<<" from holding track "<<minS<<" to output"<<endl;
    minH=n+2;
    for(int i=1;i<=k;i++)
    {
        if(!H[i].empty()&&(c=H[i].top())<minH){
            minH=c;
            minS=i;
        }
    }
}
bool Railroad(int p[],int n,int k){
    vector<stack<int> > H(k+1);
    int NowOut=1;
    int minH=n+1;
    int minS;
    for(int i=1;i<=n;i++){
        if(p[i]==NowOut){
            cout<<"Move car "<<p[i]<<" from input to output"<<endl;
            NowOut++;
            while(minH==NowOut){
                Output(minH,minS,H,k,n);
                NowOut++;
            }
        }
        else{
            if(!Hold(p[i],minH,minS,H,k,n))
                return false;
        }

    }
    return true;
}
int main(){
    int p[10] = {0369247185};
    cout << "Input permutation is 0369247185" << endl;
    Railroad(p,9,3);
}

(4)开关盒布线

View Code
#include <iostream>
#include <stack>
using namespace std;
bool CheckBox(int net[],int n){
    stack<int> s;
    for(int i=0;i<n;i++){
        if(s.empty()){
            s.push(i);
        }
        else{
            if(net[i]==net[s.top()]){
                cout<<"Wiring from "<<(i+1)<<" to "<<(s.top()+1)<<endl;
                s.pop();
            }
            else
                s.push(i);
        }
    }
    if(s.empty()) {
        cout<<"Switch box is routbale"<<endl;
        return true;
    }
    else {
        cout<<"Switch box is not routbale";
        return false;
    }
}
int main(){
    int net[]={1,2,2,1,3,3,4,4};
    int n=sizeof(net)/sizeof(net[0]);
    CheckBox(net,n);
}

(5)离线等价类

View Code
#include <iostream>
#include <list>
#include <stack>
#include <vector>
using namespace std;
int main(){
    int n,r;
    cout<<"Enter number of elements"<<endl;
    cin>>n;
    if(n<2){
        cerr<<"Too few elements"<<endl;
        return 1;
    }
    cout<<"Enter number of relations"<<endl;
    cin>>r;
    if(r<1){
        cerr<<"Too few relations"<<endl;
        return 1;
    }
    vector<list<int> > chain(n+1);
    for(int i=1;i<=r;i++)
    {
        cout<<"Enter next relation/pair"<<endl;
        int a,b;
        cin>>a>>b;
        chain[a].push_front(b);
        chain[b].push_front(a);
    }
    stack<int> s;
    vector<boolout(n+1);
    for(int i=1;i<=n;i++)
        out[i]=false;
    for(int i=1;i<=n;i++){
        if(!out[i]){
            cout<<"Next class is:"<<i<<' ';
            out[i]=true;
            s.push(i);
            list<int>::const_iterator it;
            while(!s.empty()){
                int j=s.top();
                s.pop();
                for(it=chain[j].begin();it!=chain[j].end();++it)
                    if(!out[*it]){
                        cout<<*it<<' ';
                        out[*it]=true;
                        s.push(*it);
                    }
            }
            cout<<endl;
        }
    }
    
}

(6)迷宫老鼠

View Code
#include <iostream>
#include <fstream>
#include <stack>
#include <cstdio>
using namespace std;
struct Position{
        int x;
        int y;
};
Position operator+(Position& a,Position& b){
    Position p;
    p.x=a.x+b.x;
    p.y=a.y+b.y;
    return p;
}

int **maze,m;
bool **flag;
stack<Position> path;
const char *const red = "\033[0;40;31m";
const char *const normal = "\033[0m";

template <class T>
void make2darray(T ** &maze,int w,int h){
    maze=new T*[w];
    T *mem=new T[w*h];
    for(int i=0;i<w;i++)
        maze[i]=mem+i*h;
}

template <class T>
void free2darray(T** maze){
    if(maze){
        if(*maze)
            delete[] *maze;
        delete[] maze;
    }
}
bool InputMaze(const char *file)
{// Input the maze.
    ifstream inf(file);
    inf >> m;
    cout << " maze size: "<<m<< endl;
    make2darray(maze, m, m);
    for (int i=0; i<m; i++)
        for (int j=0; j<m; j++) 
            inf >> maze[i][j];
    cout << "the maze:" << endl;
    for (int i=0; i<m; i++) {
        for (int j=0; j<m; j++) 
            cout<< maze[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
    make2darray(flag, m, m);
    for (int i=0; i<m; i++) 
        for (int j=0; j<m; j++) 
            flag[i][j]=false;

    return true;
}                                                        
void OutputPath()                                         
{// Output path to exit.
    cout << "The path is" << endl;
    Position here;
    while (!path.empty()) {
        here=path.top();
        path.pop();
        cout << here.x << ' ' << here.y << endl;
        flag[here.x][here.y]=true;
    }
    cout<<"Another:"<<endl;
    for (int i=0; i<m; i++) {
        for (int j=0; j<m; j++) 
        {
            if(flag[i][j])
                printf("%s%d%s ",red,maze[i][j],normal);
            else
                printf("%d ",maze[i][j]);
        }
        printf("\n");
    }
    printf("\n");
    
}
bool FindPath(){
    Position here={0,0};
    
    Position offset[4]={{0,1},{1,0},{0,-1},{-1,0}};
    maze[0][0]=1;
    int i=0;
    while(here.x!=m-1||here.y!=m-1){
        Position location;
        int lx,ly;
        while(i<4){
            location=here+offset[i];
            lx=location.x;
            ly=location.y;
            if(!(lx<0||ly<0||lx>m-1||ly>m-1)){
                if(maze[lx][ly]==0)
                    break;
            }
            i++;
        }
        if(i<4){
            path.push(here);
            here=location;
            maze[lx][ly]=1;
            i=0;
        }
        else{
            if(path.empty())
                return false;
            Position next;
            next=path.top();
            path.pop();
            if(next.x==here.x)
                i=2+next.y-here.y;
            else
                i=3+next.x-here.x;
            here=next;
        }
    }
    path.push(here);
    return true;
}
int main(){
    InputMaze("maze.dat");                       
    if (FindPath()) OutputPath();
    else cout << "No path" << endl;
    free2darray(maze);
    free2darray(flag);
}

迷宫数据:

10
0 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 0 1 0 0
0 0 0 1 0 1 0 0 0 0
0 1 0 1 0 1 0 1 1 0
0 1 0 1 0 1 0 1 0 0
0 1 1 1 0 1 0 1 0 1
0 1 0 0 0 1 0 1 0 1
0 1 0 1 1 1 0 1 0 0
1 0 0 0 0 0 0 1 0 0
0 0 0 0 1 1 1 1 0 0 

程序输出如下:

第6章 队列
队列是一个先进先出( first-in-first-out, FIFO)的线性表
1. 公式化实现队列
实现代码:

View Code
#include <iostream>
using namespace std;
template <class T>
class Queue{
    public:
        Queue(int Size=10);
        ~Queue(){
            delete [] queue;
        }
        bool IsEmpty()const{
            return front==rear;
        }
        bool IsFull()const{
            return ((rear+1)%MaxSize==front)?true:false;
        }
        T First()const;
        T Last()const;
        Queue<T>& Add(const T& x);
        Queue<T>& Delete(T& x);
    private:
        int front;
        int rear;
        int MaxSize;
        T *queue;
};
template <class T>
Queue<T>::Queue(int size)
{
    MaxSize=size;
    queue=new T[size];
    front=rear=0;
}
template <class T>
T Queue<T>::First()const
{
    if(IsEmpty())
        throw "Out of Bounds";
    return queue[(front+1)%MaxSize];

}
template <class T>
T Queue<T>::Last()const
{
    if(IsEmpty())
        throw "Out of Bounds";
    return queue[rear];

}
template <class T>
Queue<T>& Queue<T>::Add(const T& x)
{
    if(IsFull())
        throw "No memorry";
    rear=(rear+1)%MaxSize;
    queue[rear]=x;
    return *this;
}
template <class T>
Queue<T>& Queue<T>::Delete(T& x)
{
    if(IsEmpty())
        throw "Out of Bounds";
    front=(front+1)%MaxSize;
    x=queue[front];
    return *this;
}
int main(void)
{
   Queue<int> Q(3);
   int x;
   try {Q.Add(1).Add(2).Add(3).Add(4);
        cout << "No queue add failed" << endl;}
   catch (...)
      {cout << "A queue add failed" << endl;}
   cout << "Queue is now 123" << endl;
   Q.Delete(x);
   cout << "Deleted " << x << endl;
   cout << Q.First() << " is at front" << endl;
   cout << Q.Last() << " is at end" << endl;
   try {
      Q.Delete(x);
      cout << "Deleted " << x << endl;
      Q.Delete(x);
      cout << "Deleted " << x << endl;
      Q.Delete(x);
      cout << "Deleted " << x << endl;
      cout << "No queue delete failed " << endl;
      }
   catch (...)
      {cout << "A delete has failed" << endl;}
}
                                                           
                                                           

2. 链表描述
实现代码:

View Code
#include <iostream>
using namespace std;
template <class T>
class LinkedQueue;
template <class T>
class Node{
    friend class LinkedQueue<T>;
    private:
    T data;
    Node<T> *link;
};
template <class T>
class LinkedQueue{
    public:
        LinkedQueue(){
            front=rear=0;
        }
        ~LinkedQueue();
        bool IsEmpty()const{
            return (front)?false:true;
        }
        bool IsFull()const;
        T First()const;
        T Last()const;
        LinkedQueue<T>& Add(const T& x);
        LinkedQueue<T>& Delete(T& x);
    private:
        Node<T>*front;
        Node<T>*rear;
};
template <class T>
LinkedQueue<T>::~LinkedQueue()
{
    Node<T>*next;
    while(front){
        next=front->link;
        delete front;
        front=next;
    }
}
template <class T>
bool LinkedQueue<T>::IsFull()const
{
    Node<T>*p;
    try{
        p=new Node<T>;
        delete p;
        return false;
    }
    catch(...){
        return true;
    }
}
template <class T>
T LinkedQueue<T>::First()const
{
    if(IsEmpty())
        throw "Out of Bounds";
    return front->data;

}
template <class T>
T LinkedQueue<T>::Last()const
{
    if(IsEmpty())
        throw "Out of Bounds";
    return rear->data;

}
    template <class T>
LinkedQueue<T>& LinkedQueue<T>::Add(const T& x)
{
    Node<T>*p=new Node<T>;
    p->data=x;
    p->link=0;
    if(front) rear->link=p;
    else
        front=p;
    rear=p;
    return *this;

}
    template <class T>
LinkedQueue<T>& LinkedQueue<T>::Delete(T& x)
{
    if(IsEmpty())
        throw "Out of Bounds";
    x=front->data;
    Node<T>*p;
    p=front->link;
    delete front;
    front=p;
    return *this;
}
int main(void)
{
   LinkedQueue<int> Q;
   int x;
   try {Q.Add(1).Add(2).Add(3).Add(4);
        cout << "No queue add failed" << endl;}
   catch (...)
      {cout << "A queue add failed" << endl;}
   cout << "Queue is now 1234" << endl;
   Q.Delete(x);
   cout << "Deleted " << x << endl;
   cout << Q.First() << " is at front" << endl;
   cout << Q.Last() << " is at end" << endl;
   try {
      Q.Delete(x);
      cout << "Deleted " << x << endl;
      Q.Delete(x);
      cout << "Deleted " << x << endl;
      Q.Delete(x);
      cout << "Deleted " << x << endl;
      cout << "No queue delete failed " << endl;
      }
   catch (...)
      {cout << "A delete has failed" << endl;}
}
                                                                    

3. 队列的应用
(1)火车重排

View Code
//using queue
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
bool Hold(int c,int &minH,int& minQ,vector<queue<int> >& H,int k){
    int BestTrack=0,BestLast=0,x;
    for(int i=1;i<=k;i++){
        if(!H[i].empty()){
            x=H[i].back();
            if(c>x&&x>BestLast){
                BestLast=x;
                BestTrack=i;
            }
        }
        else{
            if(!BestTrack)
                BestTrack=i;
        }
    }
    if(!BestTrack)
        return false;
    H[BestTrack].push(c);
    cout<<"Move car "<<c<<" from input to holding track "<<BestTrack<<endl;
    if(c<minH) {
        minH=c;
        minQ=BestTrack;
    }
    return true;
}
void Output(int& minH,int& minQ,vector<queue<int> >& H,int k,int n){
    int c;
    c=H[minQ].front();
    H[minQ].pop();
    cout<<"Move car "<<minH<<" from holding track "<<minQ<<" to output"<<endl;
    minH=n+2;
    for(int i=1;i<=k;i++)
    {
        if(!H[i].empty()&&(c=H[i].front())<minH){
            minH=c;
            minQ=i;
        }
    }
}
bool Railroad(int p[],int n,int k){
    vector<queue<int> > H(k);
    k--;
    int NowOut=1;
    int minH=n+1;
    int minQ;
    for(int i=1;i<=n;i++){
        if(p[i]==NowOut){
            cout<<"Move car "<<p[i]<<" from input to output"<<endl;
            NowOut++;
            while(minH==NowOut){
                Output(minH,minQ,H,k,n);
                NowOut++;
            }
        }
        else{
            if(!Hold(p[i],minH,minQ,H,k))
                return false;
        }

    }
    return true;
}
int main(){
    int p[10] = {0369247185};
    cout << "Input permutation is 0369247185" << endl;
    Railroad(p,9,3);
}

不使用队列的实现:

View Code
//with LIFO tracks
//no explicted queue used
#include <iostream>
#include <vector>
using namespace std;
bool Hold(int c,vector<int>& last,vector<int>& track,int k){
    int BestTrack=0,BestLast=0;
    for(int i=1;i<=k;i++){
        if(last[i]){
            if(c>last[i]&&last[i]>BestLast){
                BestLast=last[i];
                BestTrack=i;
            }

        }
        else{
            if(!BestTrack)
                BestTrack=i;
        }
    }
    if(!BestTrack)
        return false;
    track[c]=BestTrack;
    last[BestTrack]=c;
    cout<<"Move car "<<c<<" from input to holding track "<<BestTrack<<endl;
    return true;
}
void Output(int NowOut,int Track,int& Last){
    cout<<"Move car "<<NowOut<<" from holding track "<<Track<<" to output"<<endl;
    if(NowOut==Last)
        Last=0;
}
bool Railroad(int p[],int n,int k){
    vector<int> last(k+1);
    vector<int> track(n+1);
    for(int i=1;i<=k;i++)
        last[i]=0;
    for(int i=1;i<=n;i++)
        track[i]=0;
    k--;
    int NowOut=1;
    for(int i=1;i<=n;i++){
        if(p[i]==NowOut){
            cout<<"Move car "<<p[i]<<" from input to output"<<endl;
            NowOut++;
            while(NowOut<=n&&track[NowOut]){
                Output(NowOut,track[NowOut],last[NowOut]);
                NowOut++;
            }
        }
        else{
            if(!Hold(p[i],last,track,k))
                return false;
        }
    }
    return true;
}
int main(){
    int p[10] = {0369247185};
    cout << "Input permutation is 0369247185" << endl;
    Railroad(p,9,3);
}

(2)电路布线

View Code
#include <iostream>
#include <fstream>
#include <queue>
#include <cstdio>
using namespace std;
struct Position{
        int x;
        int y;
};
Position operator+(const Position& a,const Position& b){
    Position p;
    p.x=a.x+b.x;
    p.y=a.y+b.y;
    return p;
}
bool operator==(const Position& a,const Position& b){
    return (a.x==b.x&&a.y==b.y);
}
Position operator-(const Position& a,int t){
    Position temp;
    temp.x=a.x-t;
    temp.y=a.y-t;
    return temp;
}
Position operator+(const Position& a,int t){
    Position temp;
    temp.x=a.x+t;
    temp.y=a.y+t;
    return temp;
}
istream& operator>>(istream& is,Position& ps){
    is>>ps.x>>ps.y;
    return is;
}
ostream& operator<<(ostream& os,const Position& ps){
    os<<"("<<ps.x<<","<<ps.y<<")";
    return os;
}
int **grid,m;
bool **flag;
const char *const red = "\033[0;40;31m";
const char *const normal = "\033[0m";

template <class T>
void make2darray(T ** &grid,int w,int h){
    grid=new T*[w];
    T *mem=new T[w*h];
    for(int i=0;i<w;i++)
        grid[i]=mem+i*h;
}
template <class T>
void free2darray(T** maze){
    if(maze){
        if(*maze)
            delete[] *maze;
        delete[] maze;
    }
}

bool Inputgrid(const char *file,Position& start,Position& finish)
{// Input the grid.
    ifstream inf(file);
    inf >> m;
    cout << " grid size: "<<m<< endl;
    make2darray(grid, m, m);
    inf>>start;
    inf>>finish;
    start=start-1;
    finish=finish-1;
    cout<<"start:"<<start<<endl;
    cout<<"finish:"<<finish<<endl;

    for (int i=0; i<m; i++)
        for (int j=0; j<m; j++) 
            inf >> grid[i][j];
    cout << "the grid:" << endl;
    for (int i=0; i<m; i++) {
        for (int j=0; j<m; j++) 
            cout<< grid[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
    make2darray(flag, m, m);
    for (int i=0; i<m; i++) 
        for (int j=0; j<m; j++) 
            flag[i][j]=false;
    return true;
}                                                        
void OutputPath(vector<Position>& path)                                         
{// Output path to exit.
    cout << "The path is" << endl;
    vector<Position>::const_iterator it;
    for(it=path.begin();it!=path.end();++it){
        cout<<*it<<endl;
        flag[it->x][it->y]=true;

    }
    cout<<"Another:"<<endl;
    for (int i=0; i<m; i++) {
        for (int j=0; j<m; j++) 
        {
            if(flag[i][j])
                printf("%s%d%s ",red,grid[i][j],normal);
            else
                printf("%d ",grid[i][j]);
        }
        printf("\n");
    }
    printf("\n");
    
}
bool FindPath(const Position& start,const Position& finish,vector<Position>& path){
  //  if((start.x==finish.x)&&(start.y==finish.y)){
    if((start==finish)){
        return true;
    }
    Position here=start;
    Position nbr;
    
    const int NumOfNbrs=4;
    Position offset[]={{0,1},{1,0},{0,-1},{-1,0}};

    grid[start.x][start.y]=2;
    queue<Position> Q;
    int lx,ly;
    do{
        for(int i=0;i<NumOfNbrs;i++){
            nbr=here+offset[i];
            lx=nbr.x;
            ly=nbr.y;
            if(!(lx<0||ly<0||lx>m-1||ly>m-1)){
                if(grid[nbr.x][nbr.y]==0){
                    grid[nbr.x][nbr.y]=grid[here.x][here.y]+1;
                    if(nbr==finish)
                        break;
                    Q.push(nbr);
                }
            }
        }
        if(nbr==finish)
            break;
        if(Q.empty())
            return false;
        here=Q.front();
        Q.pop();
    }while(1);
    int PathLen=grid[finish.x][finish.y]-2;
    path.resize(PathLen);
    here=finish;
    for(int j=PathLen-1;j>=0;j--){
        path[j]=here;
        for(int i=0;i<NumOfNbrs;i++){
            nbr=here+offset[i];
            lx=nbr.x;
            ly=nbr.y;
            if(!(lx<0||ly<0||lx>m-1||ly>m-1)){
                if(grid[nbr.x][nbr.y]==j+2)
                    break;
            }
        }
        here=nbr;
    }
    return true;
}
int main(){
    Position start,finish;
    Inputgrid("wire.dat",start,finish);                       
    vector<Position> path;
    if (FindPath(start,finish,path))
        OutputPath(path);
    else
        cout << "No path" << endl;
    free2darray(grid);
    free2darray(flag);
}

布线路图:

 
7
3 2
4 6
0 0 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 0 0
1 0 0 0 1 0 0
1 1 1 0 0 0 0
1 1 1 0 0 0 0 

程序输出如下:

(3)识别图元

View Code
#include <iostream>
#include <fstream>
#include <queue>
#include <cstdio>
using namespace std;
struct Position{
        int x;
        int y;
};
Position operator+(const Position& a,const Position& b){
    Position p;
    p.x=a.x+b.x;
    p.y=a.y+b.y;
    return p;
}
int **pixel,m;
const char *color[]={ "\033[0;40;31m","\033[0;40;32m","\033[0;40;33m","\033[0;40;34m","\033[0;40;35m","\033[0;40;36m"};
const char *const normal = "\033[0m";

template <class T>
void make2darray(T ** &pixel,int w,int h){
    pixel=new T*[w];
    T *mem=new T[w*h];
    for(int i=0;i<w;i++)
        pixel[i]=mem+i*h;
}
template <class T>
void free2darray(T** maze){
    if(maze){
        if(*maze)
            delete[] *maze;
        delete[] maze;
    }
}

void InputImage(const char*file)
{// Input the pixel.
    ifstream inf(file);
    inf >> m;
    cout << " pixel size: "<<m<< endl;
    make2darray(pixel, m, m);

    for (int i=0; i<m; i++)
        for (int j=0; j<m; j++) 
            inf >> pixel[i][j];
    cout << "the pixel:" << endl;
    for (int i=0; i<m; i++) {
        for (int j=0; j<m; j++) 
            cout<< pixel[i][j];
        cout<<endl;
    }
    cout<<endl;
}                                                        
void OutputImage()                                         
{// Output path to exit.
    cout<<"Another:"<<endl;
    for (int i=0; i<m; i++) {
        for (int j=0; j<m; j++) 
        {
            if(pixel[i][j]>1)
                printf("%s%d%s ",color[pixel[i][j]-2],pixel[i][j],normal);
            else
                printf("%d ",pixel[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}
void Label(){
    const int NumOfNbrs=4;
    Position offset[]={{0,1},{1,0},{0,-1},{-1,0}};
    Position here,nbr;
    queue<Position> Q;
    int id=1;
    for(int r=0;r<m;r++){
        for(int c=0;c<m;c++){
            if(pixel[r][c]==1){
                pixel[r][c]=++id;
                here.x=r;
                here.y=c;
                int lx,ly;
                do{
                    for(int i=0;i<NumOfNbrs;i++){
                        nbr=here+offset[i];
                        lx=nbr.x;
                        ly=nbr.y;
                        if(!(lx<0||ly<0||lx>m-1||ly>m-1)){
                            if(pixel[lx][ly]==1){
                                pixel[lx][ly]=id;
                                Q.push(nbr);
                            }
                        }
                    }
                    if(Q.empty())
                        break;
                    here=Q.front();
                    Q.pop();
                }while(1);
            }
        }
    }
}
int main(){
    const char*file="image.dat";
    InputImage(file);
    cout << "The input image is" << endl;
    OutputImage();
    Label();
    cout << "The labeled image is" << endl;
    OutputImage();
}

图元数据:

7
0 0 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 0 0
1 0 0 0 1 0 0
1 1 1 0 0 0 0
1 1 1 0 0 0 0

程序输出:

第7章 跳表和散列
1. 线性表来实现字典,该线性表按关键字从左到右依次增大。
View Code
#include <iostream>
using namespace std;
template <class E, class K> class SortedChain;                      

template <class E, class K>
class SortedChainNode {
    friend class SortedChain<E,K>;
    private:
    E data;
    K key;
    SortedChainNode<E,K> *link;
};
template<class E,class K>
class SortedChain{
    public:
        SortedChain(){
            first=0;
        }
        ~SortedChain();
        bool IsEmpty()const{
            return first==0;
        }
        int Length()const;
        bool Search(const K& k,E& e)const;
        SortedChain<E,K>& Delete(const K& k,E& e);
        SortedChain<E,K>& Insert(const K& k,const E& e);
        SortedChain<E,K>& DistinctInsert(const K&k,const E& e);
        void Output(ostream& outconst;
    private:
        SortedChainNode<E,K> *first;
};
template<class E,class K>
SortedChain<E,K>::~SortedChain()
{
    SortedChainNode<E,K>* next;
    while(first){
        next=first->link;
        delete first;
        first=next;
    }
}
template<class E,class K>
int SortedChain<E,K>::Length()const
{
    SortedChainNode<E,K>* p=first;
    int len=0;
    while(p){
        p=p->link;
        len++;
    }
    return len;

}
template<class E,class K>
bool SortedChain<E,K>::Search(const K& k,E& e)const
{
    SortedChainNode<E,K> *p=first;
    while(p&&p->key<k)
        p=p->link;
    if(p&&p->key==k) {
        e=p->data;
        return true;
    }
    return false;
}
template<class E,class K>
SortedChain<E,K>& SortedChain<E,K>::Delete(const K& k,E& e)
{
    SortedChainNode<E,K>*p=first,*tp=0;
    while(p&&p->key<k){
        tp=p;
        p=p->link;
    }
    if(p&&p->key==k){
        e=p->data;
        if(tp)
            tp->link=p->link;
        else
            first=p->link;
        delete p;
        return *this;
    }
    throw "Bad Input";
    return *this;

}
template<class E,class K>
SortedChain<E,K>& SortedChain<E,K>::Insert(const K& k,const E& e)
{
    SortedChainNode<E,K>*p=first,*tp=0;
    while(p&&p->key<k){
        tp=p;
        p=p->link;
    }
    SortedChainNode<E,K> *q=new SortedChainNode<E,K>;
    q->key=k;
    q->data=e;
    q->link=p;
    if(tp)
        tp->link=q;
    else
        first=q;
    return *this;
}
template<class E,class K>
SortedChain<E,K>& SortedChain<E,K>::DistinctInsert(const K& k,const E& e)
{
    SortedChainNode<E,K>*p=first,*tp=0;
    while(p&&p->key<k){
        tp=p;
        p=p->link;
    }
    if(p&&p->data==e)
        throw "Bad Input";
    SortedChainNode<E,K> *q=new SortedChainNode<E,K>;
    q->key=k;
    q->data=e;
    q->link=p;
    if(tp)
        tp->link=q;
    else
        first=q;
    return *this;
}
template<class E,class K>
void SortedChain<E,K>::Output(ostream& outconst
{
    SortedChainNode<E,K>*p;
    p=first;
    while(p){
        out<<"("<<p->key<<","<<p->data<<"";
        p=p->link;
    }
}
template<class E,class K>
ostream& operator<<(ostream& out,const SortedChain<E,K>& x){
    x.Output(out);
    return out;
}

int main(void)
{
    SortedChain<intint> Z;                                           
    int x;
    Z.Insert(2,2).Insert(6,6).Insert(4,4);
    cout << "The chain is " << Z << endl;
    cout << "Its length is " << Z.Length() << endl;
    Z.Delete(2,x);
    cout << "Deleted " << x << endl;
    cout << Z << endl;
    Z.Insert(1,1).Delete(6,x);
    cout << Z << endl;
    Z.Insert(8,8).Insert(9,9).Search(8,x);
    cout << "Found " << x << endl;
    Z.Insert(7,7).Delete(9,x);
    cout << Z << endl;
    try {Z.DistinctInsert(7,7);}
    catch (...)
    {cout << "Attempt to insert duplicate element" << endl;}
    cout << Z << endl;
    Z.DistinctInsert(10,10);
    cout << Z << endl;
}
2. 跳表描述
(1)理想情况
(2)插入删除
(3)级的分配
(4)复杂性

跳表的实现代码:

View Code
#if 1
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;
template <class E,class K>
class SkipList;
template <class E,class K>
class SkipNode{
    friend class SkipList<E,K>;
    SkipNode(int size){
        link=new SkipNode<E,K>*[size];
    }
    ~SkipNode(){
        delete[] link;
    }
    private:
    E data;
    K key;
    SkipNode<E,K>**link;
};
template<class E,class K>
class SkipList{
    public:
       SkipList(K large,int MaxE=10000,float p=0.5);
       ~SkipList();
       bool Search(const K& k,E& e)const;
       SkipList<E,K>& Insert(const K& k,const E& e);
       SkipList<E,K>& Delete(const K& k,E& e);
       void Output();
    private:
       int Level();
       SkipNode<E,K>* SaveSearch(const K& k);
       int MaxLevel;
       int Levels;
       int CutOff;
       K TailKey;
       SkipNode<E,K>* head;
       SkipNode<E,K>* tail;
       SkipNode<E,K>* *last;
};
template<class E,class K>
SkipList<E,K>::SkipList(K large,int MaxE,float p)
{
    CutOff=p*RAND_MAX;
    MaxLevel=ceil(log(MaxE*1.0)/log(1/p))-1;
    TailKey=large;
    Levels=0;
    
    head=new SkipNode<E,K>(MaxLevel+1);
    tail=new SkipNode<E,K>(0);
    last=new SkipNode<E,K>* [MaxLevel+1];
    tail->key=large;
    for(int i=0;i<=MaxLevel;i++)
        head->link[i]=tail;
}
template<class E,class K>
SkipList<E,K>::~SkipList()
{
    SkipNode<E,K> *next;
    while(head!=tail){
        next=head->link[0];
        delete head;
        head=next;
    }
    delete tail;
    delete [] last;
}
template<class E,class K>
bool SkipList<E,K>::Search(const K& k,E& e)const
{
    if(k>=TailKey)
        return false;
    SkipNode<E,K> *p=head;
    for(int i=Levels;i>=0;i--)
        while(p->link[i]->key<k)
            p=p->link[i];

    e=p->link[0]->data;
    K tmp=p->link[0]->key;
    return e==tmp;
}
template<class E,class K>
SkipList<E,K>& SkipList<E,K>::Insert(const K& k,const E& e)
{
    if(k>=TailKey)
        throw "Bad Input";
    SkipNode<E,K> *p=SaveSearch(k);
    if(p->data==e)
        throw "Bad Input";
    int lev=Level();
    if(lev>Levels){
        lev=++Levels;
        last[lev]=head;
    }
    SkipNode<E,K> *y=new SkipNode<E,K>(lev+1);
    y->data=e;
    y->key=k;
    for(int i=0;i<=lev;i++){
        y->link[i]=last[i]->link[i];
        last[i]->link[i]=y;
    }
    return *this;
}
template<class E,class K>
SkipList<E,K>& SkipList<E,K>::Delete(const K& k,E& e)
{
    if(k>=TailKey)
        throw "Bad Input";
    SkipNode<E,K> *p=SaveSearch(k);
    if(p->data==e)
        throw "Bad Input";
    for(int i=0;i<=Levels&&last[i]->link[i]==p;i++)
        last[i]->link[i]=p->link[i];
    while(Levels>0&&head->link[Levels]==tail)
        Levels--;
    e=p->data;
    delete p;
    return *this;
}
template<class E,class K>
int SkipList<E,K>::Level()
{
    int lev=0;
    while(rand()<=CutOff)
        lev++;
    return lev<=MaxLevel?lev:MaxLevel;
}
template<class E,class K>
SkipNode<E,K>* SkipList<E,K>::SaveSearch(const K& k)
{
    SkipNode<E,K> *p=head;
    for(int i=Levels;i>=0;i--){
        while(p->link[i]->key<k)
            p=p->link[i];
        last[i]=p;
    }
    return p->link[0];
}
template<class E, class K>
void SkipList<E,K>::Output()
{
    SkipNode<E,K> *y = head->link[0];
    for (; y != tail; y = y->link[0])
        cout <<"("<<y->key<<","<< y->data <<"";
    cout << endl;
}


int main(void)
{
   SkipList<intlong> S(100011000.5);
   int i, n = 20;
   int data;
   long key;
   for (i = 1; i <= n; i++) {
      data = i; 
      key = 2*i;
      S.Insert(key,data);
   }
   S.Output();
   for (i=1; i <= n+1; i++) {
      data = n+i; 
      key = 2*i-1;
      try {S.Insert(key,data);}
      catch (...)
       {cout << "Unable to insert duplicate (" <<key<<","<<data<<")"<< endl;}
      }
   
   S.Output();
   for (i = 1; i <= n+1; i++) {
      key = 2*i-1;
      try {S.Delete(key,data);
         cout << "Deleted (" << key << "," << data <<")"<< endl;}
      catch (...)
         {cout << "Delete of " << (2*i-1) << " failed" << endl;}
      }
   S.Output();
}
#endif
3. 散列表描述/哈希表
(1)线性开型寻址
View Code
#include <iostream>
using namespace std;
template<class E,class K>
class HashTable{
    public:
        HashTable(int divisior=11);
        ~HashTable(){
            delete[] ht;
            delete[] empty;
        }
        bool Search(const K& k,E& e)const;
        HashTable<E,K>& Insert(const E& e);
        void Output();
    private:
        int hSearch(const K& k)const;
        int D;
        E *ht;
        bool *empty;
};
template<class E,class K>
HashTable<E,K>::HashTable(int divisior)
{
    D=divisior;
    ht=new E[D];
    empty=new bool[D];
    for(int i=0;i<D;i++)
        empty[i]=true;
}
template<class E,class K>
bool HashTable<E,K>::Search(const K& k,E& e)const
{
    int b=hSearch(k);
    if(empty[b]||ht[b]!=k)
        return false;
    e=ht[b];
    return true;

}
template<class E,class K>
HashTable<E,K>& HashTable<E,K>::Insert(const E& e)
{
    K k=e;
    int b=hSearch(k);
    if(empty[b]){
        empty[b]=false;
        ht[b]=e;
        return *this;
    }
    if(ht[b]==k)
        throw "Bad Input";
    throw "No mem";
    return *this;
}
template<class E,class K>
void HashTable<E,K>::Output()
{
    for(int i=0;i<D;i++){
        if(empty[i])
            cout<<"empty"<<endl;
        else
            cout<<ht[i]<<endl;
    }

}
template<class E,class K>
int HashTable<E,K>::hSearch(const K& k)const
{
    int i=k%D;
    int j=i;
    do{
        if(empty[j]||ht[j]==k)
            return j;
        j=(j+1)%D;
    }
    while(j!=i);
    return j;
}
int main(void)
{  
    int data;
    long key;
   HashTable<intlong> h(11);
   data= 80;
   h.Insert(data);
   data= 40;
   h.Insert(data);
   data= 65;
   h.Insert(data);
   h.Output();
   data= 58;
   h.Insert(data);
   data= 24;
   h.Insert(data);
   cout << ' ' << endl;
   h.Output();
   data= 2;
   h.Insert(data);
   data= 13;
   h.Insert(data);
   data= 46;
   h.Insert(data);
   data= 16;
   h.Insert(data);
   data= 7;
   h.Insert(data);
   data= 21;
   h.Insert(data);
   cout << ' ' << endl;
   h.Output();
   data=99;
   try {h.Insert(data);}
   catch (...)
      {cout  << " No memory for 99" << endl;}
}                                                         

(2)链表散列

View Code
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
template <class K,class E>
class ChainHashTable{
    public:
        ChainHashTable(int div=11):D(div){
            tab.resize(div);
        }
        bool Search(const K& k,E& e)const{
            typename map<K,E>::iterator ite;
            ite=tab[k%D].find(k);
            if(ite==tab[k%D].end())
                return false;
            e=ite->second;
            return true;
        }
        ChainHashTable& Insert(const K& k,const E& e){
            tab[k%D].insert(pair<K,E>(k,e));
            return *this;
        }
        ChainHashTable& Delete(const K& k){
            tab[k%D].erase(k);
            return *this;
        }
        void Output(ostream& os)const{
            typename map<K,E>::const_iterator ite;
            for(int i=0;i<D;i++){
                os<<"tab["<<i<<"]:";
                for(ite=tab[i].begin();ite!=tab[i].end();++ite){
                    os<<"<"<<ite->first<<","<<ite->second<<"";
                }
                os<<endl;
            }
        }
    private:
        int D;
        vector<map<K,E> > tab;
};
template <class E,class K>
ostream& operator<<(ostream& os,const ChainHashTable<E,K>& cht){
    cht.Output(os);
    return os;
}
const string letters("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
string rand_str(int n){
    string s(n,' ');
    for(int i=0;i<n;i++){
        int pos=rand()%52;
        s[i]=letters[pos];
    }
    return s;
}
int main(){
    ChainHashTable<int,string> ht(11);
    int N=20;
    for(int i=0;i<N;i++){
        int val=rand()%100;
        string str=rand_str(10);
        ht.Insert(val,str);
    }
    cout<<"ok"<<endl;
    cout<<ht<<endl;

}

实现代码采用了STL中的map:

4. 散列与跳表的比较:

5.应用

 LzW压缩

压缩代码的实现如下:下面的代码没有采用上面的等长位编码,而是采用的最显而易见的方式: 

map<string,unsigned> compress(string & in_str,string& str_code){
    map<string,unsigned> mp;
    int N=Alpha;
    int used=N;
    for(int i=0;i<N;i++){
        string key(1,'a'+i);
        unsigned code=i;
        mp.insert(pair<string,unsigned>(key,code));
    }
    typename map<string,unsigned>::iterator ite;
    ostringstream  oss;
    size_t len=in_str.length();
    if(len<2){
        ite=mp.find(in_str.substr(0,1));
        oss<<ite->second;
    }
    else{
        string pcode;
        pcode+=in_str[0];
        for(int i=1;i<len;i++){
            char c=in_str[i];
            string key=pcode+c;
            ite=mp.find(key);
            if(ite!=mp.end()){
                pcode=key;
            }
            else{
                oss<<mp[pcode];
                mp.insert(pair<string,unsigned>(key,used++));
                pcode=c;
            }
        }
        oss<<mp[pcode];
    }
    str_code=oss.str();
    return mp;
}

  LZW解压缩 

解压缩代码:与压缩代码是对应的:

map<unsigned,string> decomp(string& str_code,string& out_str){
    map<unsigned,string> mp;
    int N=Alpha;
    unsigned used=N;
    for(int i=0;i<N;i++){
        unsigned key=i;
        string code(1,'a'+i);
        mp.insert(make_pair(key,code));
    }
    typename map<unsigned,string>::iterator ite;
    ostringstream  oss;
    size_t len=str_code.length();
    if(len<2){
        oss<<mp[(unsigned)(str_code[0]-'0')];
    }
    else{
        unsigned pcode=(unsigned)(str_code[0]-'0');
        oss<<mp[pcode];
        for(int i=1;i<len;i++){
            string prefix=mp[pcode];
            char surfix;
            string code;
            unsigned key=used++;
            unsigned ccode=(unsigned)(str_code[i]-'0');
            ite=mp.find(ccode);
            if(ite!=mp.end()){
                oss<<ite->second;
                surfix=(ite->second).at(0);
                code=prefix+surfix;
//                unsigned key=used++;
//                mp.insert(make_pair(key,code));
            }
            else{
//                string prefix=mp[pcode];
                surfix=prefix[0];
                code=prefix+surfix;
//                unsigned key=used++;
                oss<<code;
            }
            mp.insert(make_pair(key,code));
            pcode=ccode;
        }
    }
    out_str=oss.str();

    return mp;
}

下面的代码是对上面压缩与解压缩的测试,包括测试压缩然后再解压缩得到的字符串与原字符串是否相等,压缩与解压所构造的字典是否一致,并给出了字典。

View Code
#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <cstdlib>
using namespace std;
const string letters("ab");//cdefghijklmnopqrstuvwxyz");
const int Alpha=2;
template <class T>
void con_print(T& c){
    typename T::iterator ite;
    for(ite=c.begin();ite!=c.end();++ite){
        cout<<*ite<<' ';
    }
    cout<<endl;
}
template <class K,class E>
void map_print(map<K,E>& mp){
    typename map<K,E>::iterator ite;
    for(ite=mp.begin();ite!=mp.end();++ite)
        cout<<"<"<<ite->first<<","<<ite->second<<">"<<' ';
    cout<<endl;
}
map<string,unsigned> compress(string & in_str,string& str_code){
    map<string,unsigned> mp;
    int N=Alpha;
    int used=N;
    for(int i=0;i<N;i++){
        string key(1,'a'+i);
        unsigned code=i;
        mp.insert(pair<string,unsigned>(key,code));
    }
    typename map<string,unsigned>::iterator ite;
    ostringstream  oss;
    size_t len=in_str.length();
    if(len<2){
        ite=mp.find(in_str.substr(0,1));
        oss<<ite->second;
    }
    else{
        string pcode;
        pcode+=in_str[0];
        for(int i=1;i<len;i++){
            char c=in_str[i];
            string key=pcode+c;
            ite=mp.find(key);
            if(ite!=mp.end()){
                pcode=key;
            }
            else{
                oss<<mp[pcode];
                mp.insert(pair<string,unsigned>(key,used++));
                pcode=c;
            }
        }
        oss<<mp[pcode];
    }
    str_code=oss.str();
    return mp;
}
map<unsigned,string> decomp(string& str_code,string& out_str){
    map<unsigned,string> mp;
    int N=Alpha;
    unsigned used=N;
    for(int i=0;i<N;i++){
        unsigned key=i;
        string code(1,'a'+i);
        mp.insert(make_pair(key,code));
    }
    typename map<unsigned,string>::iterator ite;
    ostringstream  oss;
    size_t len=str_code.length();
    if(len<2){
        oss<<mp[(unsigned)(str_code[0]-'0')];
    }
    else{
        unsigned pcode=(unsigned)(str_code[0]-'0');
        oss<<mp[pcode];
        for(int i=1;i<len;i++){
            string prefix=mp[pcode];
            char surfix;
            string code;
            unsigned key=used++;
            unsigned ccode=(unsigned)(str_code[i]-'0');
            ite=mp.find(ccode);
            if(ite!=mp.end()){
                oss<<ite->second;
                surfix=(ite->second).at(0);
                code=prefix+surfix;
//                unsigned key=used++;
//                mp.insert(make_pair(key,code));
            }
            else{
//                string prefix=mp[pcode];
                surfix=prefix[0];
                code=prefix+surfix;
//                unsigned key=used++;
                oss<<code;
            }
            mp.insert(make_pair(key,code));
            pcode=ccode;
        }
    }
    out_str=oss.str();

    return mp;
}
bool map_equal(map<string,unsigned>& mp,map<unsigned,string>& mp2){
    typename map<string,unsigned>::iterator ite;
    typename map<unsigned,string>::iterator ite2;
    for(ite=mp.begin();ite!=mp.end();++ite){
        ite2=mp2.find(ite->second);
        if(ite->first!=ite2->second)
            return false;
    }
    return true;
}
int main1(){
    string in_str("aaabbbbbbaabaaba");
    string str_code;
    map<string,unsigned> mp=compress(in_str,str_code);
    cout<<in_str<<":"<<str_code<<endl;
    map_print(mp);

    return 0;
}
int main2(){
    string str_code("0214537");
    string out_str;
    map<unsigned,string> mp=decomp(str_code,out_str);
    cout<<str_code<<":"<<out_str<<endl;
    map_print(mp);
    return 0;
}
int main(){
    int N=15;
    for(int i=0;i<50;i++){
        string in_str(N,' ');
        for(int j=0;j<N;j++)
            in_str[j]=letters[rand()%2];
        string str_code;
        map<string,unsigned> mp=compress(in_str,str_code);
        string out_str;
        map<unsigned,string> mp2=decomp(str_code,out_str);

        cout<<in_str<<" ";
        cout<<str_code<<" ";
        cout<<out_str<<" ";
        if(in_str==out_str)
            cout<<"OK ";
        else
            cout<<"NO ";
        if(map_equal(mp,mp2))
            cout<<"OK ";
        else
            cout<<"NO ";
        map_print(mp2);
    }

}

  下面是一个测试结果示例:

每一个行中的两个OK表示字符串是否一致,字典是否一致。 最后的是字典。

这儿存在的一个问题是:字符串不要太长,不然如果之巅长度超过10以后编码就乱了,因为编码之后的数字之间是没有空格进行分隔的。解决方法是可以换一种编码方式,可以采用大写字母。

上面的截图中也出现了字典长度超过10的情况,但是压缩和解压的结果仍然一致,原因是因为最后一个映射没有用到。

 

posted @ 2012-06-28 16:28  Mr.Rico  阅读(316)  评论(0编辑  收藏  举报