Chủ Nhật, 20 tháng 5, 2012

Queue -Hang Doi

Posted by Unknown Chủ Nhật, tháng 5 20, 2012, under |


Hàng đợi :(tiếng Anh: queue) là một cấu trúc dữ liệu dùng để chứa các đối tượng làm việc theo cơ chế FIFO (viết tắt từ tiếng Anh:First In First Out), nghĩa là "vào trước ra trước
Trong hàng đợi, các đối tượng có thể được thêm vào hàng đợi bất kỳ lúc nào, nhưng chỉ có đối tượng thêm vào đầu tiên mới được phép lấy ra khỏi hàng đợi. Thao tác thêm vào và lấy một đối tượng ra khỏi hàng đợi được gọi lần lượt là "enqueue" và "dequeue". Việc thêm một đối tượng luôn diễn ra ở cuối hàng đợi và một phần tử luôn được lấy ra từ đầu hàng đợi.
Trong tin học, cấu trúc dữ liệu hàng đợi có nhiều ứng dụng: khử đệ qui, tổ chức lưu vết các quá trình tìm kiếm theo chiều rộng và quay lui, vét cạn, tổ chức quản lý và phân phối tiến trình trong các hệ điều hành, tổ chức bộ đệm bàn phím.
Cấu trúc dữ liệu hàng đợi có thể định nghĩa như sau: Hàng đợi là một cấu trúc dữ liệu trừu tượng (ADT) tuyến tính. Tương tự nhưngăn xếp, hàng đợi hỗ trợ các thao tác:
EnQueue(o): thêm đối tượng o vào cuối hàng đợi.
DeQueue(): lấy đối tượng ở đầu queue ra khỏi hàng đợi và trả về giá trị của nó. Nếu hàng đợi rỗng thì lỗi sẽ xảy ra.
IsEmpty(): kiểm tra xem hàng đợi có rỗng không.
Front(): trả về giá trị của phần tử nằm ở đầu hàng đợi mà không hủy nó. Nếu hàng đợi rỗng thì lỗi sẽ xảy ra.
Các thao tác thêm, trích và huỷ một phần tử phải được thực hiện ở hai phía khác nhau của hàng đợi, do đó hoạt động của hàng đợi được thực hiện theo nguyên tắc FIFO. Cũng như ngăn xếp, cấu trúc mảng một chiều hoặc cấu trúc danh sách liên kết có thể dùng để biểu diễn cấu trúc hàng đợi.

Có 2 cách cài đặt hàng đợi:
- Dùng mảng.
- Dùng danh sách liên kết.
1. Cài đặt hàng đợi sử dụng mảng (Implementation Queue using Array)
a) Mảng bình thường:
 #include <stdio.h>
 #include <stdlib.h>
 #define MAX 20
 typedef <Element's type> El_type;
 typedef struct Queue
 {
     El_type el[MAX];
     int front;
     int rear;
 } Queue;
Các thao tác: - Khởi tạo hàng đợi( Initialize Queue )
 Eltype *initQ( Queue *q )
 {
     q = (Queue *)malloc( sizeof( Queue ) );
     if( q != NULL ) 
     {
          q->front = -1;
          q->rear = -1;
     }
     return q;
 }
- Kiểm tra xem hàng đợi có rỗng không? ( Check if a queue is empty )
 int isEmpty( Queue *q )
 {
     return ( q->front == -1 );
 }
- Kiểm tra xem hàng đợi có đầy không? ( Check if a queue is full )
 int isFull( Queue q )
 {
     return ( q.rear-q.front+1 == MAX);
 }
- Đưa thêm một phần tử vào hàng đợi
 void enQ( El_type new_el, Queue *q )
 {
     if( !isFull( q ) )
     {
          if( isEmpty( q ) ) q->front = q->front+1;
          q->rear = q->rear+1;
          q->el[q->rear] = new_el;
     }
     else
          printf( "Queue is full.\n" );
 }
- Xóa một phần tử khỏi hàng đợi
 void deQ( Queue *q )
 {
     if( !isEmpty( q ) )    
         q->front = q->front+1;           
     else
         printf( "Queue is empty.\n" );
 }
Nhược điểm:
- Qua mỗi lần xóa (deQ): phần sử dụng được của mảng sẽ giảm đi (do front tăng lên ).
Cách khắc phục:
- Sử dụng mảng vòng (Circular Array).
Mảng vòng:
 tương ta có:
- Khởi tạo hàng đợi( Initialize Queue )
 Eltype *initQ( Queue *q )
 {
     q = (Queue *)malloc( sizeof( Queue ) );
     if( q != NULL ) 
     {
          q->front = -1;
          q->rear = -1;
     }
     return q;
 }
- Kiểm tra xem hàng đợi có rỗng không? ( Check if a queue is empty )
 int empty_queue(queue q)
 {
   return q.front==-1;
 }
- Kiểm tra xem hàng đợi có đầy không? ( Check if a queue is full )
 int full_queue(queue q)
 {
   return (q.rear-q.front+1)%maxlength==0;
 }
- Đưa thêm một phần tử vào hàng đợi
 void enqueue(elementtype x,queue *q)
 {
   if(!full_queue(*q))
   {
     if(empty_queue(*q))q->front=0;
     q->rear=(q->rear+1)%maxlength;
     q->data[q->rear]=x;                 
   }
   else printf("Hang Day!");
 }
- Xóa một phần tử khỏi hàng đợi
 void dequeue(queue *q)
 {
   if(!empty_queue(*q))
   {
     if(q->front==q->rear)makenull_queue(q);
     else q->front=(q->front+1)%maxlength;
   }
   else printf("Hang rong!");
 }
Nhược điểm:
- Mặc dù phương pháp sử dụng mảng vòng có thể tận dùng toàn bộ các mảng đã được cấp pháp ban đầu nhưng khi mảng đầy thì không thể thêm phần tử vào hàng được nữa. Cách khắc phục:
- Sử dụng Danh sách liên kết.
Cài Đặt Mảng Sử Dụng Danh Sách Liên Kết: (Implementation Queue using List Point)
Khai báo cài đặt hàng bằng con trỏ
 #include <stdio.h>
 #include <conio.h>
 #include <malloc.h>
 typedef int elementtype;
 typedef struct node{
   elementtype data;
   node* next;
 };
 typedef node* position;
 typedef struct queue{
   position front,rear;      
 };
Các thao tác:
- Khởi tạo hàng đợi( Initialize Queue )
 void makenull_queue(queue *q)
 {
   q->front=(node*)malloc(sizeof(node));
   q->front->next=NULL;
   q->rear=q->front;
 }
- Kiểm tra xem hàng đợi có rỗng không? ( Check if a queue is empty )
 int empty_queue(queue q)
 {
   return (q.front==q.rear);  
 }
- Kiểm tra hàng đợi có đầy không (ở đây không có hàm này vì danh sách liên kết làm sao đầy được ^^!)
- Đưa thêm một phần tử vào hàng đợi
 void enqueue(elementtype x, queue *q)
 {
   q->rear->next=(node*)malloc(sizeof(node));
   q->rear=q->rear->next;
   q->rear->data=x;
   q->rear->next=NULL;   
 }
- Xóa một phần tử khỏi hàng đợi
 void dequeue(queue *q)
 {
   position t;
   t=q->front;
   q->front=q->front->next;
   free(t);
 }
Ưu điểm: - khắc phục được tình trạng đầy của việc sử dụng mảng để cài đặt queue.



Chuyen Bieu Thuc Trung To Sang Hau To

Posted by Unknown Chủ Nhật, tháng 5 20, 2012, under |


Phương pháp chuyển đổi biểu thức inFix sang postFix như sau : (Trích sách Cấu trúc dữ liệu và thuật toán )
Nếu thành phần được đọc là toán hạng thì viết nó vào biểu thức postFix
Nếu thành phần được đọc là dấu mở ngoặc thì đẩy nó vào stack
Nếu thành phần được đọc là dấu đóng ngoặc thì lấy các phép toán trong stack ra và viết nó vào biểu thức postFix cho tới khi gặp dấu mở ngoặc.
Sau đó loại dấu mở ngoặc khỏi stack
Nếu thành phần là phép toán thì xét các trường hợp sau
Nếu stack không rỗng, hoặc phần tử ở đỉnh stack có độ ưu tiên cao hơn hay bằng phép toán hiện thời thì lấy phép toán đó ra khỏi stack và đưa vào postFix. Lặp lại bước này
Nếu stack rỗng, hoặc phần tử ở đỉnh stack có độ ưu tiên thấp hơn phép toán hiện thời thì phép toán hiện thời được đẩy vào stack
Sau khi toàn bộ biểu thức inFix đã được đọc thì lấy các phép toán trong ngăn xếp ra và viết vào postFix cho đến khi ngăn xếp rỗng
Dưới đây là code của mình viết theo thuật toán trên:



#include <iostream>
#include <string.h>
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
#define  SIZE  100 
const int TOAN_TU = 1;
const int TOAN_HANG = 0; 
int LayDoUuTien(char toantu); // Ham tra ve do uu tien cua toan tu
//** Ham xu ly stack **//
char Top(char stack[]); //Tra ve phan tu dau tien trong stack nhung khong xoa khoi stack
void Push(char phantu, char stack[]); //Dat 1 phan tu vao stack
char Pop(char stack[]); //Lay phan tu dau tien ra khoi stack
/* Ham noi 1 ky tu vao cuoi chuoi.*/
void ConCat(char kytu, char array[]);
/*
* Ham kiem tra ky tu elem co phai la toan tu khong?
* Tra ve 1 neu elem la toan tu.
* Nguoc lai tra ve 0.
*/


int LoaiPhanTu(char elem);
/**
* Chuyen 1 chuoi infix sang chuoi postfix
*/
void InfixToPostFix(char infix[], char postfix[]);
/*
* Tinh gia tri postfix.
* @param postfix[]: chuoi chua postfix
*/


float TinhGiaTriBieuThuc(char postfix[]);
/**
* Tinh gia tri cua phep toan 2 ngoi
*/
float TinhGiaTri(char toantu, float val1, float val2);
int main() 
{
char infix[SIZE];


char postfix[SIZE];
//xoa vung nho chua postfix
strcpy(infix, "");
cout<<"note: \n";
cout<<" chi nhap toan tu tu 0 den 9\n";
cout << "nhap bieu thuc:";
cin >> infix; 
InfixToPostFix(infix, postfix);
cout << "Postfix: " << postfix <<endl;
cout <<"Gia tri: ";
cout <<TinhGiaTriBieuThuc(postfix);
getch();
return 0;


}

void InfixToPostFix(char infix[], char postfix[])
{
char stack[SIZE];
strcpy(postfix, "");
strcpy(stack, "");
int len = strlen(infix);
for (int i = 0; i < len; i++) 
{
char curChar = infix[i];
if (LoaiPhanTu(curChar) == TOAN_TU) 
{
int rank1 = LayDoUuTien(curChar);
int rank2 = LayDoUuTien(Top(stack));
if (rank1 > rank2) 
{


Push(curChar, stack);
} else
{


//Lay cac toan tu co do uu tien thap hon ra khoi stack
//va bo vao postfix
while (rank1 <= rank2)
{


if (Top(stack) == ' ')
break;
//lay phan tu tu` stack bo vao postfix


ConCat(Pop(stack), postfix);
//Kiem tra phan tu ke tiep trong stack


rank2 = LayDoUuTien(Top(stack));


}
Push(curChar, stack);


}
} else if (curChar == '(')
{


Push(curChar, stack);
} else if (curChar == ')') 
{


char temp = Pop(stack);


while (temp != '(')
{


ConCat(temp, postfix);


temp = Pop(stack);


}


} else //toan hang


{


ConCat(curChar, postfix);


}
}

//lay nhung phan tu con lai trong stack


while (Top(stack) != ' ') 
{


ConCat(Pop(stack), postfix);


}
}
int LoaiPhanTu(char elem)
 {
if (elem == '+' || elem == '-' || elem == '*' || elem == '/')
 {
return TOAN_TU;
}
return TOAN_HANG;
}
int LayDoUuTien(char toantu) 
{
int iRes = -1;
switch (toantu) 
{


case '*':


case '/':


iRes = 5;


break;


case '+':


case '-':


iRes = 4;


break;


default:


iRes = 0;


}
return iRes;


}
char Top(char stack[]) 
{


int len = strlen(stack);


if (len > 0) 
{
return stack[len-1];


}
return ' '; // neu stack rong, tra ve ky tu trong


}
char Pop(char stack[]) 
{
int len = strlen(stack);
if (len > 0)
{


char cRes = stack[len-1];


stack[len-1] = '\0';
return cRes;


}
return ' ';
}

void Push(char phantu, char stack[])
 {
int len = strlen(stack);
stack[len] = phantu;


stack[len+1] = '\0';


}
void ConCat(char kytu, char array[]) {


Push(kytu, array);
}
float TinhGiaTriBieuThuc(char postfix[]) {


float stackGiaTri[SIZE];


int dinh = -1; // vi tri di?nh cua stack
int len = strlen(postfix);
for (int i = 0; i < len; i++)
 {
char curChar = postfix[i];


if (LoaiPhanTu(curChar) == TOAN_HANG) {


char ss[2];


ss[0] = curChar;


ss[1] = '\0';


float val = atof(ss);


dinh++;


stackGiaTri[dinh] = val;

else if (LoaiPhanTu(curChar) == TOAN_TU) {


float val2 = stackGiaTri[dinh];


dinh--;

if (dinh < 0) {


cout << "Bieu thuc co loi.";


exit(-1);


}
float val1 = stackGiaTri[dinh];


float val3 = TinhGiaTri(curChar, val1, val2);


stackGiaTri[dinh] = val3;


}
}
if (dinh > 0) 
{
cout << "Bieu thuc khong dung";


exit(-1);
}
return stackGiaTri[dinh];
}
float TinhGiaTri(char toantu, float val1, float val2)
{
float fRes = 0;

switch (toantu)
{


case '*':


fRes = val1 * val2; break;


case '/': 
{


if (val2 == 0) 
{


cout << "Loi chia cho 0"; exit(-2);


}
fRes = val1 / val2; break;
}
case '+':


fRes = val1 + val2; break;


case '-':


fRes = val1 - val2; break;


break;
}
return fRes;

Bai Toan Thap HaNoi

Posted by Unknown Chủ Nhật, tháng 5 20, 2012, under |

BÀI TOÁN THÁP HÀ NỘI - TOWER OF HANOI:


Có thể còn ít người Việt Nam biết Tháp Hà Nội, nhưng rất nhiều thanh niên sinh viên trên toàn thế giới lại biết đến nó. Đó là vì, Tháp Hà Nội là tên một bài toán rất nổi tiếng trong Chương trình khoa học tính toán (Computing Science) dành cho sinh viên những năm đầu tại các trường đại học ở nhiều nơi trên thế giới.


Tương truyền rằng ngày xửa ngày xưa, lâu lắm rồi, ở một vùng xa xôi viễn đông, thành phố Hà Nội của Việt Nam, vị quân sư của Hoàng đế vừa qua đời, Hoàng đế cần một vị quân sư mới thay thế. Bản thân Hoàng đế cũng là một nhà thông thái, nên ngài đặt ra một bài toán đố, tuyên bố ai giải được sẽ được phong làm quân sư. Bài toán của Hoàng đế là: cho n cái đĩa (ngài không nói chính xác là bao nhiêu) và ba cái trục: A là trục nguồn, B là trục đích, và C là trục trung chuyển. Những cái đĩa có kích cỡ khác nhau và có lỗ ở giữa để có thể lồng vào trục, theo quy định "nhỏ trên lớn dưới". Đầu tiên, những cái đĩa này được xếp tại trục A. Vậy làm thế nào để chuyển toàn bộ các đĩa sang trục B, với điều kiện chuyển từng cái một và luôn phải đảm bảo quy định "nhỏ trên lớn dưới", biết rằng trục C được phép sử dụng làm trục trung chuyển? 


Vì địa vị quân sư được coi là vinh hiển nên có rất nhiều người dự thi. Từ vị học giả đến bác nông phu, họ đua nhau trình lên Hoàng đế lời giải của mình. Nhiều lời giải dài tới hàng nghìn bước, và nhiều lời giải có chữ "chuyển sang bước tiếp theo" (go to). Nhưng hoàng đế thấy mệt mỏi vì những lời giải đó, nên cuối cùng hạ chiếu: "Ta không hiểu những lời giải này. Phải có một cách giải nào khác dễ hiểu và nhanh chóng hơn". May mắn thay, cuối cùng đã có một cách giải như thế.
Thật vậy, ngay sau khi chiếu vua ban ra, một vị cao tăng trông bề ngoài giống như một kỳ nhân hạ sơn tới xin yết kiến hoàng đế. Vị cao tăng nói: "Thưa Bệ hạ, bài toán đố đó dễ quá, hầu như nó tự giải cho nó". Quan trùm cấm vệ đứng hầu ngay bên cạnh vua quắc mắt nhìn gã kỳ nhân, muốn quẳng gã ra ngoài, nhưng Hoàng đế vẫn kiên nhẫn tiếp tục lắng nghe. "Nếu chỉ có 1 đĩa, thì...; nếu có nhiều hơn 1 đĩa (n>1), thì...", cứ thế vị cao tăng bình tĩnh giảng giải. Im lặng được một lát, cuối cùng Hoàng đế sốt ruột gắt: "Được, thế cao tăng có nói rõ cho ta lời giải hay không cơ chứ?". Thay vì giải thích tiếp, gã kỳ nhân mỉm cười thâm thúy rồi biến mất, bởi vì hoàng đế tuy giỏi giang nhưng rõ ràng là chưa hiểu ý nghĩa của phép truy hồi (recursion). Nhưng các bạn sinh viên ngày nay thì có thể thấy cách giải của vị cao tăng là hoàn toàn đúng.


Toàn bộ đoạn chữ nghiêng ở trên được trích nguyên văn từ cuốn sách giáo khoa dành cho sinh viên ngành thuật toán và lập trình - "giải toán nâng cao và cấu trúc dữ liệu" (intermediate problem solving and data structures) do Paul Henman và Robert Veroff, hai giáo sư Đại học New Mexico, cùng biên soạn với Frank Carrano, giáo sư Đại học Rhode Island (Mỹ).

Bạn nào chưa từng biết Tháp Hà Nội thì cũng nên "thử sức" một chút xem sao, vì đây là một trò chơi rất thú vị. Bạn có thể bắt đầu bằng bài toán 3 đĩa, rồi nâng lên 4 đĩa. Với 4 đĩa chắc bạn bắt đầu thấy rắc rối. Nâng tiếp lên 5 và cao hơn nữa, chẳng hạn n = 1 triệu, bài toán sẽ rắc rối đến mức không ai đủ kiên trì và đủ thì giờ để thử từng đĩa một. Vậy mà vị cao tăng dám nói là dễ quá! Xin tiết lộ, ấy là vì vị đó đã sử dụng phép truy hồi - một quy tắc toán học cho phép xác định số hạng thứ n từ số hạng đứng trước nó, tức số hạng thứ n-1. Cái giỏi của vị cao tăng là ông tìm ra một quy tắc chung, tức một thuật toán chung cho tất cả các bước chuyển đĩa. 


Vậy thay vì mô tả toàn bộ quá trình chuyển đĩa từng cái một như những thí sinh trước đó đã làm, vị cao tăng chỉ mô tả một quy tắc chung. Cứ làm theo quy tắc đó, lặp đi lặp lại chẳng cần suy nghĩ gì, rồi cuối cùng tự nhiên sẽ tới đích. Vì thế vị cao tăng nói rằng bài toán này "tự nó giải nó".


Trong khoa học tính toán ngày nay, phép truy hồi là thuật toán cơ bản để lập trình. Ưu điểm của phương pháp truy hồi là ở chỗ nó dùng một công thức nhất định để diễn tả những phép tính lặp đi lặp lại bất chấp số lần lặp lại là bao nhiêu. Nếu số lần lặp lại lên đến con số hàng triệu hàng tỷ thì con người không đủ sức và thời gian để làm, nhưng máy tính thì có thể giải quyết trong chớp mắt. Điểm mạnh của computer là ở chỗ nó không hề biết e ngại và mệt mỏi trước những công việc lặp đi lặp lại lên đến hàng triệu hàng tỷ lần. Và vì thế, việc cộng tác giữa computer với con người là mô hình lý tưởng của lao động trí óc trong cuộc sống hiện đại.


Về mặt lịch sử, Tháp Hà Nội được E. Lucas phát hiện từ năm 1883, nhưng mãi đến gần đây người ta mới nhận ra ý nghĩa hiện đại của nó. Hiện vẫn chưa rõ vì sao Lucas lại gọi chồng đĩa trong bài toán là Tháp Hà Nội, mà không gọi là Tháp Bắc Kinh, hay Tháp Tokyo. 


Tháp Hà Nội đã mở tung cánh cửa cho tương lai khi nhiều nghiên cứu lấy Tháp Hà Nội làm điểm xuất phát đã đạt được thành tựu mới: 


(1) Nâng câu hỏi của Tháp Hà Nội lên một mức cao hơn, sao cho số lần chuyển đĩa là nhỏ nhất. Các nhà toán học đã phát hiện ra rằng Tháp Hà Nội có cùng bản chất với bài toán tìm Đường Hamilton (Hamilton Path) trên một hình giả phương cấp n (n-Hypercube), một bài toán cũng rất nổi tiếng. 


(2) Nhà toán học D.G. Poole đã sáng tạo ra Lược Đồ Hà Nội - một tam giác có các đỉnh tương ứng với các cách sắp xếp đĩa trong Tháp Hà Nội, từ đó tìm ra những liên hệ lý thú giữa Tam giác Pascal với Lược đồ Hà Nội. Liên hệ này đã được công bố trong một công trình mang một cái tên đầy liên tưởng: Pascal biết Hà Nội (Pascal knows Hanoi).


Hiện nay, tại một số đại học ở Australia, uy tín của sinh viên Việt Nam trong lĩnh vực lập trình được đánh giá ngang với sinh viên Ấn Độ - một cường quốc lập trình của thế giới, làm cho Tháp Hà Nội vốn đã nổi tiếng lại càng nổi tiếng hơn.

Cách giải Bài toán:

Bài toán có 2 chiều, chiều nghịch dùng để phân tích bài toán và dùng để lập trình, chiều thuận để thực hiện trên mô hình. Ở đây nguyên lí thực hiện (tức là cách hiểu bài toán) nằm ở chiều nghịch, còn cách thực hiện nằm ở chiều thuận. Chiều nghịch dùng cho dân lập trình và chiều thuận dành cho dân toán. 
Chiều nghịch thì dân lập trình hay gọi là bài toán đệ qui. Bài toán này có ví dụ đơn giản như sau: giaithừa(n)=giaithừa(n-1)*n. Muốn tính giai thừa của n thì đơn giản, lấy n nhân với giai thừa của (n-1). Còn giai thừa của (n-1) thì tính sao? Đơn giản, cứ lấy (n-1) nhân với giai thừa của (n-2) …

- Chiều nghịch (nguyên lí): Muốn đưa n khối tròn từ cột A (cột nguồn) sang cột C (cột đích) thông qua cột B (cột trung gian) thì chỉ cần đưa (n-1) khối tròn từ A qua B, rồi đưa 1 khối tròn từ A qua C và cuối cùng là đưa (n-1) khối tròn từ B qua C. Đã làm xong bài toán!!!
Còn (n-1) khối tròn từ A sang B thì làm sao mà đưa? Đơn giản, khi đó xem A là cột nguồn, B là cột đích và C là cột trung gian. Việc tiến hành tương tự, đưa (n-2) khối từ cột nguồn qua cột trung gian, 1 khối từ cột nguồn sang cột đích và cuối cùng là (n-2) khối từ cột trung gian sang cột đích. Còn về source code thì sao, xin xem phần sau cùng vì nếu viết ở đây sẽ có thể gây rối một vài bạn đọc không được học về lập trình.

- Chiều thuận: Nói đơn giản để hiệu thì như chiều nghịch đã nói. Còn thực hiện (chiều thuận) thì làm sao? Khối tròn đầu tiên từ cột nguồn A thì chuyển vào đâu? Cột trung gian B hay cột đích C?
Với khối tròn đầu tiên thì chuyển về cột đích (với n là số lẻ) và cột trung gian (với n là số chẳn). Xếp được 1 khối tròn (khối nhỏ nhất) theo đúng yêu cầu thì tiếp theo là xếp 2 khối tròn theo đúng yêu cầu (2 khối nhỏ nhất và nhỏ nhì). Cứ xếp 2 khối đó vào cột còn lại so với lần đầu tiên và làm tiếp vớ 3, 4, … khối tròn. 


Phát triển của cách làm trên: Muốn chuyển n khối tròn từ cột nguồn sang cột đích thì làm như sau (ở đây ta phải hiểu rõ cột nguồn không nhất thiết là cột A, cột đích là C hay cột trung gian là B mà phải hiểu tổng quát, có thể cột nguồn là B chẳng hạn (trong phép chuyển (n-1) cột từ cột B sang cột C như trong cách làm ở phần nghịch)):
Với n lẻ: cách xếp các khối như sau. Đầu tiên là xếp được 1 khối nhỏ nhất (bài toán với n=1). Sau đó xếp 2 khối nhỏ nhất (bài toán với n=2) ….
• 1 khối nhỏ nhất qua cột đích
• 2 khối nhỏ nhất qua cột trung gian
• 3 khối nhỏ nhất qua cột đích
• 4 khối nhỏ nhất qua cột trung gian
• Tiếp tục như trên
Với n chẳn: cách xếp các khối như sau. Đầu tiên là xếp được 1 khối nhỏ nhất (bài toán với n=1). Sau đó xếp 2 khối nhỏ nhất (bài toán với n=2) ….
• 1 khối nhỏ nhất qua cột trung gian
• 2 khối nhỏ nhất qua cột đích
• 3 khối nhỏ nhất qua cột trung gian
• 4 khối nhỏ nhất qua cột đích
• Tiếp tục như trên
- Như vậy thì số lần chuyển cho bài toán là bao nhiêu? Với bài toán tháp Hà Nội chuyển n khối tròn từ cột nguồn A sang cột đích C thông qua cột trung gian B thì cần có 2^0 + 2^1 + 2^2 + … + 2^n lần chuyển


4  đĩa

3 đĩa

code C++
// ThapHaNoi.cpp : Defines the entry point for the console application.
// So dia nhap vao voi may tinh cau hinh hien tai thi khoang 50, o day minh gioi han la 10

#include "stdafx.h"

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#define MAX 50
//Khai bao cau truc cho thap Ha Noi
//Bao gom:so dia,coc nguon,coc dich
typedef struct HaNoi
{
int n;//So dia can di chuyen
int Nguon;//Cot bat dau di chuyen
int Dich;//Cot duoc chuyen den
int Tam;//cot trung gian
}ThapHaNoi;
//Dinh nghia lai du lieu
typedef ThapHaNoi DataType;
//Khai bao cau truc cho node
typedef struct node
{
DataType info;
struct node*Next;
}Node;
//Dinh nghia lai node
typedef Node *NodePtr;
NodePtr pTop;
/*
typedef struct Stack{
NodePtr pTop;
}STACK; */
//pTop=NULL;
//Khoi tao stack
//Ban dau stack rong
void initStack(NodePtr &pTop)
{
pTop=NULL ;
}
NodePtr NewNode()
{
NodePtr newnode;
newnode=(NodePtr)malloc(sizeof(Node));
return newnode;
}
NodePtr CreateNode(DataType x)
{
NodePtr p=(NodePtr)malloc(sizeof(Node)) ;
p->info=x;
p->Next=NULL;
return p;
}
//Kien tra stack rong?
int isEmpty(NodePtr pTop)
{
if(pTop==NULL)
return 1;
else
return 0;
}
//Gai phong stack
void FreeNode(NodePtr p)
{
free(p);
}
//Lay phan tu dau stack
ThapHaNoi Pop(NodePtr &pTop)
{
NodePtr p;
DataType value;
if(isEmpty(pTop))
{
printf("Stack is empty");
}
else
p=pTop;//Luu phan tu dau stack vao p
pTop=pTop->Next;//Cap nhat lai pTop
value=p->info;
FreeNode(p);
return value;
}
//Dua phan tu vao stack
void Push(NodePtr &pTop,DataType x)
{
NodePtr node;
node=NewNode();
node->info=x;
node->Next=pTop;
pTop=node;
}

/*HaNoi Top(NodePtr pTop)
{
DataType value;
if(isEmpty(pTop))
{
printf("Stack is empty");
//return -1;
}
value=pTop->info;
return value5;
} */
//Thap Ha Noi
//Du lieu dau vao
//n:so dia can di chuyen,ng:cot nguon chua dia can di chuyen
//d:cot dich can chuyen den
//t:cot trung gian
void HaNoi(int &n)
{
NodePtr pTop;//Stack chua thong tin di chuyen
initStack(pTop);//Khoi tao stack
//Dua bai toan ban dau vao stack
ThapHaNoi hn;
hn.n=n;
hn.Nguon=1;
hn.Dich=2;
hn.Tam=3;
Push(pTop,hn);
while(!isEmpty(pTop))
{
hn=Pop(pTop);//Lay phan tu dau stack
//Truong hop chi co 1 dia,thi di chuyen dia nguon->dich
if(hn.n==1)
printf("\nDi chuyen dia tu cot %d -> %d",hn.Nguon,hn.Dich);
//Truong hop co nhieu hon 1 dia
else
{
ThapHaNoi hn1;
//ThapHaNoi hn1,hn2,hn3;
//Dua thong tin di chuyen n-1 dia tu tam(cot trung gian) -> dich
hn1.n=hn.n-1;
hn1.Nguon=hn.Tam;
hn1.Dich=hn.Dich;
hn1.Tam=hn.Nguon;
Push(pTop,hn1);
//Dua thong tin di chuyen 1 dia tu nguon -> dich
hn1.n=1;
hn1.Nguon=hn.Nguon;
hn1.Dich=hn.Dich;
hn1.Tam=hn.Tam;
Push(pTop,hn1);
//Dua thong tin di chuyen n-1 dia tu nguon -> tam(trung gian)
hn1.n=hn.n-1;
hn1.Nguon=hn.Nguon;
hn1.Dich=hn.Tam;
hn1.Tam=hn.Dich;
Push(pTop,hn1);
}
}
}
void main()
{
int n;
printf("\t \t CHUONG TRINH MINH HOA THAP HA NOI BANG STACK \n \n \n");

do{
printf("\n Nhap vao so dia(1->10):");
scanf("%d",&n);
if(n>10)
{
printf(" \n So dia qua lon xin vui long nhap lai");
}
else
HaNoi(n);
}while(n>10);

getch();
}







Chuyen Doi Co So Dung Stack

Posted by Unknown Chủ Nhật, tháng 5 20, 2012, under |


// DoiCoSoDungStack.cpp : Defines the entry point for the console application.
// Nhap vao la so nguyen duong; co so la  nhi phan (2), bat phan (8), thap luc (16)


#include "stdafx.h"
#include <stdio.h>
#include <conio.h>

typedef long ele;

struct Node
{
   ele data;
   Node*next;
};
typedef Node *Stack;



//khoi tao ngan xep
void CreateStack(Stack &S)
{
   S = NULL;
}

//kiem tra rong

bool EmptyStack(Stack S)
{
   return (S==NULL);
}


//khoi tao node
Stack CreateNode(ele x)
{
   Stack p =new(Node);
   if(!p)
   {
      printf("Loi cap phat.."); return NULL;
   }
   p->data = x;
   p->next = NULL;
}
//chen push
void Push(Stack &S,ele x)
{
   Node*p = CreateNode(x);
   if(! EmptyStack(S))
      p->next = S;
   S=p;

}

//lay doi tuong dau va xoa
void Pop(Stack &S,ele &x)
{
   if(EmptyStack(S))
   {
      printf("Rong "); return;
   }
   Node*p=S;
   x=p->data;
   S=S->next;
   delete (p);

}

//lay ma ko xoa

void Top(Stack S,ele &x)
{
   if(EmptyStack(S))
   {
      printf("rong ");
      return;
   }
   x=S->data;
}




void Doicoso(Stack &S,ele so,ele coso)
{
 
   CreateStack(S);
   while(so>0)
   {
      int du =so%coso;
      Push(S,du);
      so=so/coso;
   }
 
}


void OutPut(Stack S)
{
   if(S==NULL)
   {
      printf("DS rong ");
      return;
   }
 
   Stack p = S;

   while(p!= NULL)
   {
      switch (p->data)
      {
      case 0:printf(" --> %d",p->data ); break;
      case 1 :printf(" --> %d",p->data ); break;
      case 2:printf(" --> %d",p->data ); break;
      case 3: printf(" --> %d",p->data ); break;
      case 4 : printf(" --> %d",p->data ); break;
      case 5: printf(" --> %d",p->data ); break;
      case 6:printf(" --> %d",p->data ); break;
      case 7 :printf(" -- >%d",p->data ); break;
      case 8:printf(" --> %d",p->data ); break;
      case 9 :printf(" --> %d",p->data ); break;      
      default: // neu so du la 10 thi printf la A, 11 la B ...
         printf(" --> %c",'A' + p->data - 10);
      }
      p=p->next;
   }

}

int _tmain(int argc, _TCHAR* argv[]) // khi viet code o C++ tu phien ban 2010 khong dung void main()
{
   Stack S;
 
   ele so,coso;
   printf("\n Nhap so nguyen duong can doi: ");
   scanf("%d",&so);
   printf("\n Nhap co so doi: ");
   scanf("%d",&coso);

   Doicoso(S,so,coso);
   printf("so %ld doi tu he 10 sang he %d  : " ,so,coso);
   OutPut(S);
   printf("\n \n");
 

    getch();
return 0;
}



Xem Nhiều

Bài đăng phổ biến

Lưu trữ blog

Blog Archive