Giải đáp thắc mắc - Trao đổi kinh nghiệm về C++

Thảo luận trong 'Lập trình & Đồ hoạ' bắt đầu bởi anhvu_2410, 13/11/07.

  1. NapoleonBonapart

    NapoleonBonapart Mr & Ms Pac-Man

    Tham gia ngày:
    16/11/06
    Bài viết:
    161
    Nơi ở:
    đảo Corsica
    Các bác cho em hỏi ai có link nào có sách dạy Visual C++ 2005 không vậy cho em với. Em muốn học C++ nhưng lại không kiếm đâu ra sách học cả.
    Mod ơi em kiếm mãi không biết chỗ nào để bỏ bài này vào nên cho nó ké tạm ở đây nhé.
     
  2. Newsboy

    Newsboy Mr & Ms Pac-Man

    Tham gia ngày:
    19/8/06
    Bài viết:
    291


    Code này đúng rồi. chỉ có điều là ngồi ngắm nó hoài mà chả hỉu nổi.Debug thì cũng bó tay vì hv(1,n) là hàm con 8-}
    Ai biết thì Debug cái code này =lời văn giúp em với
    thx nhìu.
     
  3. Bối Bối

    Bối Bối C O N T R A

    Tham gia ngày:
    20/2/06
    Bài viết:
    1,859
    Nơi ở:
    Ha Noi, Vietnam,
    knowfree.net
    sách đủ thể loại
    link rapidshare

    goodluck
     
  4. pmphuong

    pmphuong Mr & Ms Pac-Man

    Tham gia ngày:
    10/1/05
    Bài viết:
    278
    Xem code của người khác là tương đối mệt! Vì thế khi làm bài cố gắng đặt tên biến sao cho nó gợi lên được nội dung mà nó phải mang. Ngoài ra có chú thích cho người khác dễ hiểu. Tôi rất ít khi sử dụng biến Global. Thường các bạn cảm thấy biến cục bộ khó sử dụng, lằng nhằng. Dùng global chỉ việc khai báo một lần sau đó cứ thế mà dùng. Tuy nhiên khi người khác nhìn code của bạn ở trong một cái hàm nào đó mà nó sử dụng một cái biến được khai báo ở tít tên đầu thật là khó khăn, lại phải lật lên tận đầu tiên. Thử tưởng tượng bạn viết chương trình có độ chục cái hàm thôi là tương đối mệt cho người xem. Ngoài ra bạn hoàn toàn có thể tạo điều kiện cho những ai theo dõi diễn đàn giúp bạn bằng cách post nội dung cái lỗi đó lên, giúp ích rất nhiều cho người đọc!
     
  5. Newsboy

    Newsboy Mr & Ms Pac-Man

    Tham gia ngày:
    19/8/06
    Bài viết:
    291
    ..........................................................
     
  6. pmphuong

    pmphuong Mr & Ms Pac-Man

    Tham gia ngày:
    10/1/05
    Bài viết:
    278
    He he! Sorry! Tôi không để ý! Vừa trông bot vừa coi :D! Để mà hiểu đoạn code này chắc bạn phải nghiên cứu lại lý thuyết đi thôi! Nếu tui nhớ không nhầm thì để in ra được cái hoán vị này thì phải dùng thuật toán tìm hoán vị kế. Chi tiết và cụ thể thì tui chịu. Đại loại là xây dựng một quy tắc nào đó cho các hoán vị này. Dựa trên quy tắc đó nếu cho ta một hoán vị nào đó thì ta sẽ chỉ ra hoán vị kế ngay sau nó.

    Để dễ hiểu hơn ta đi lấy luôn bài tìm hoán vị của (A1,A2,...An) làm ví dụ vừa dễ hiểu lại vừa tổng quát! Trước hết ta tìm hiểu thế nào là hoán vị đứng trước, hoán vị đứng sau.

    Ta xây dựng quy tắc so sánh hai hoán vị như sau:
    + So sánh hai phần tử đầu tiên của hai hoán vị với nhau
    + Nếu phần tử đầu tiên bằng nhau thì xét phần tử kế tiếp ngay sau nó.
    + Nếu thực hiện lại bước 2 nếu kết quả là bằng nhau.
    + Giả sử đến phần tử thứ i kết quả không còn bằng nhau nữa thì hoán vị nào có phần tử lớn hơn là hoán vị lớn hơn (hay là hoán vị đứng trước)
    - Một phần tử lớn hơn phần tử khác nếu chỉ số của nó lớn hơn.
    Lấy một vài ví dụ cho dễ hiểu:
    + So sánh 2 phần tử
    - An > An-1
    - A5 > A1
    - An > An-1 > An-2 > An-3 .... A1
    + So sánh 2 hoán vị:
    - A=(A5,A2,A3,A1,A4) > B=(A4,A5,A3,A2,A1) vì phần tử đầu tiên của A lớn hơn phần tử đầu tiên của hoán vị B là A4.
    - A=(A5,A4,A3,A2,A1) > B=(A5,A4,A3,A1,A2) dễ thấy 3 phần tử đầu tiên là giống nhau nhưng phần tử thứ 4 của A là A2 lớn hơn phần thử thứ 4 của B là A1.

    Từ quy tắc trên ta thấy hoán vị lớn nhất là hoán vị (An,An-1,An-2....A1)
    hoán vị nhỏ nhất là hoán vị
    (A1,A2,A3,....An)

    Câu hỏi đặt ra là làm sao tìm được hoán vị kế tiếp nhỏ hơn ngay sau một hoán vị bất kì dựa vào quy tắc trên? Bây giờ ta sẽ đi tìm một hoán kế ngay sau một hoán vị bất kì!

    Dễ thấy rằng một hoán vị bất kì bao giờ cũng thỏa mãn (.....,Ak1,Ak2,Ak3,....,Akm)
    Trong đó Aki (i=1-->m) thuộc trong bộ (An,An-1,....A1) và thỏa mãn Aki-1>Aki với m lớn nhất có thể.
    + Lấy vài ví dụ cho dễ hiểu.
    - (....A4,A1,A2,A3) m=3
    - (....A9,A2,A4,A5,A8) m=4
    - (....A4,A9,A2,A5,A1,A6) m=1

    Rõ ràng hoán vị bất kì nào cũng có dạng trên, tối thiểu là m= 1.

    Ta lại còn thấy m là lớn nhất thỏa mãn điều trên từ đây => ngay trước Ak1 là một Ax nào đó mà chắc chắn một điều là Ax > Ak1
    Ta sẽ hình dung như sau:
    Ax > Ak1 < Ak2 < Ak3 < .... Akm

    Đằng trước của Ax là gì ta không cần quan tâm vì ta không thay đổi gì cả.

    Ta làm một việc như sau. Thử chèn Ax vào dãy Ak1 < Ak2 ... < Akm mà vẫn đảm bảo tính tăng dần của dãy xem Ax nó nằm ở chỗ nào!

    Rõ ràng Ax có thể nằm giữa Ak1 và Ak2 như thế này : Ak1 < Ax < Ak2
    hoặc Ax nằm ở cuối dãy Akm < Ax
    Không quan trọng ta giả sử nó nằm giữa 2 phần tử Aki và Aki+1 như thế ta sẽ có dãy như thế này:
    Ak1 < Ak2 < Ak 3 < .... < Aki < Ax < Aki+1 < ... Akm
    Ok! Hiển nhiên chẳng khó khăn gì khi xác định i nếu ta dùng vòng lặp. Khi có được i ta làm thao tác như sau. Đưa Aki lên đầu dãy như thế ta sẽ có dãy:
    Aki > Ak1 < Ak2 < Ak3 <... < Ax < Aki+1 <... Akm
    Và thêm một thao tác cuối cùng là giữ nguyên Aki vào đảo ngược dãy đằng sau thành giảm giần như sau:
    Aki Akm > Akm-1 > .... > Aki+1> Ax > ....> Ak2 > Ak1

    Đến đây ta để ý:
    - Hoán vị (Aki,Akm,Akm-1,....Ax,...Ak2,Ak1) là hoán vị lớn nhất bắt đầu bằng Aki (đố ai tìm được hoán vị lớn hơn mà bắt đầu bằng Aki đấy)
    - Hoán vị (Ax,Ak1,Ak2,Ak3...Ai,...Akm) là hoán vị nhỏ nhất bắt đầu bằng Ax (tìm được cái nào nhỏ hơn mà bắt đầu bằng Ax chết liền)
    - Có tìm được hoán vị nào nằm giữa 2 hoán vị này không? Thử xem! Nếu có thì nó phải bắt đầu bằng Aki hoặc Ax bởi vì chẳng có cái Ax nào thỏa mãn Aki<Az<Ax trong bộ (Ax,Ak1,Ak2,...Akm) cả.
    - Không có ai chen vào giữa thì hai thằng này là kế tiếp nhau rồi. Vậy là xong nhé!

    Lấy vị dụ cụ thể cho dễ hiểu nào: Hoán vị của 9 số từ 1 --> 9 nhé!

    Giả sử cho ta hoán vị: (4,2,1,8,6,3,5,7,9) dễ thấy ngay 3<5<7<9 ok! Nhưng 6>3<5<7<9! Chèn thằng 6 vào dãy 3<5<7<9 thành 3<5<6<7<9 . Lúc này Aki chính là thằng 5, đưa thằng 5 lên đầu dãy thành 5>3<6<7<9 và giữ nguyên 5 đảo dãy đằng sau thành: 5 9>7>6>3
    Có ngay hoán vị sau thằng (4,2,1,8,6,3,5,7,9) là (4,2,1,8,6,5,9,7,6,3)
    Bạn thử bỏ đoạn đầu giống nhau (4,2,1,8) và tìm thử xem có thằng nào chen nổi vào vữa hai thằng (6,3,5,7,9) và (5,9,7,6,3) ko?

    Vậy nếu ta tìm đc thằng ngay đằng sao để làm gì? Thử nghĩ xem nếu ta cho hoán vị ban đầu là hoán vị lớn nhất. Và lặp tìm hoán vị kế cho đến khi ra được thằng nhỏ nhất có phải là liệt kê hết được hoán vị của n phần tử ko? Đây chính là cơ sở để viết đoạn code này!

    Hàm h(1,v) chính là nạp hoán vị lớn nhất vào và cứ thể tìm hoán vị kết sau nó cho đến khi hết!
     
  7. Newsboy

    Newsboy Mr & Ms Pac-Man

    Tham gia ngày:
    19/8/06
    Bài viết:
    291
    [​IMG]
    ............
    Bạn giải thích cái nguyên lý mình hiểu rồi. Tiếc là thầy mình chưa dạy mấy cái cú pháp của hàm :(
     
  8. pmphuong

    pmphuong Mr & Ms Pac-Man

    Tham gia ngày:
    10/1/05
    Bài viết:
    278
    Hàm là gì? Hai cái hàm thì thành cái mồm :D!

    Ví dụ ta cứ viết tắt là CNTT, trong bài viết của mình cứ viết tắt như vậy. Đến cuối bài ta chú thích CNTT= Công Nghệ Thông Tin. Cứ tạm hiểu như vậy đi thì cũng thấy tác dụng của hàm nó thế nào! Làm cho chương trình dễ xem dễ hiểu hơn!

    Ví dụ:hàm tính tổng của 2 và 3 được viết như sau:
    void tinhtong()
    {
    int tong=0;
    clrscr();
    tong=2+3;
    printf("Tong cua 2 va 3 la:%d",tong);
    }

    Thế là xong cái hàm thật đơn giản! Có rồi thì sử dụng như thế nào và làm sao để sử dụng? Sử dụng lúc nào mình muốn thôi và để sử dụng ta chỉ cần gọi tên nó. Ví dụ một trong main ta dùng hàm tính tổng thì gọi như sau:

    main ()
    {
    tinhtong();
    }

    Ồ, dễ sử dụng kinh người! Giờ đây ta đã thấy sự lợi hại của hàm chỉ gọi mỗi một câu thôi mà nó thực hiện những 4 công việc nào là khai báo biến tong, nào là tính giá trị của 2 + 3 rồi gán cho biến tổng, nào là xóa màn hình nào là in ra thông báo.

    Lợi hai hơn, hãy tưởng tượng bạn có thể sự dụng CNTT ở nhiều chỗ trong bài viết của mình thì cũng tương tự như vậy bạn có thể dùng hàm tinhtong() nhiều lần trong main() => vừa dễ hiểu vừa tiết kiệm code. Hãy xem đoạn code sau tính tổng hai số:

    main()
    {
    int a,b;
    nhapdulieu(a,b);
    tinhtoanketqua(a,b);
    inketqua();
    }

    Tôi thề với bạn nếu bạn chẳng hiểu gì về tin học thì đọc đoạn code này cũng hiểu được nó đang làm việc gì và tiến trình làm như thế nào rất rõ ràng. Bạn viết code thì bạn nắm rõ những người khác xem rất khó ( thậm chí chính bạn vài tháng nữa xem lại chưa chắc đã hiểu đó là gì :)) ) nhưng nếu ta tổ chức chương trình như trên thì người khác xem sẽ hiểu ngay.

    Cái lợi thứ hai nếu chương trình của bạn dài, đâu thể hoàn thành trong 1 ngày được. Chẳng lẽ mỗi ngày lại phải đọc lại từ đầu để coi là mình làm đến đâu rồi à! Nhưng nếu ta tổ chức như trên ta biết ngay tiến trình công việc đồng thời lại chia nhỏ được công việc. Rõ ràng hàm nhapdulieu(a,b) hôm qua ta đã viết xong. Hôm nay chẳng cần quan tâm nữa muốn sử dụng thì gọi thôi, hôm nay ta viết hạm tinhtoanketqua().

    Chưa hết! Để làm tăng thêm sự lợi hại của hàm làm cho nó trở nên cơ động linh hoạt hơn người ta còn cho phép đưa dữ liệu từ bên ngoài vào trong hàm! Dễ dàng thấy nếu nhu cầu tính toán của ta không chỉ dừng lại ở việc tính tổng hai số 2 và 3 ta còn muốn tính tổng 3 và 4, 9 và 15... Chẳng lẽ mỗi lần như thế lại phải viết một hàm riêng cho 2 số cần tính. Không chúng ta không làm thế. Chúng ta sẽ viết một hàm duy nhất thôi. Hàm đó sẽ có dạng: Nếu tôi đưa cho anh hai số nào đó thì anh phải thực hiện tính tổng hai số đó và đưa kết quả ra màn hình.
    Như vậy muốn tính kết quả của hai số bất kì chỉ cần gọi:
    tinhtong(2,3);
    tinhtong(3,6);
    tinhtong(9,8);
    ...

    Để hàm viết ra làm được như thế thì ta phải quy định rõ ràng dữ liệu vào cho nó. Vì thế thì viết hàm cần cung cấp đầy đủ thông tin.
    Ví dụ: tinhtong( int a, int b) có nghĩa là dữ liệu vào sẽ có hai đối tượng. Đối tượng thứ nhất phải là số, không những thế còn phải là số nguyên. Đối tượng thứ 2 cũng vậy. Nếu đưa thiếu thì lỗi mà đưa sai kiểu cũng lỗi. Như vậy:
    tinhtong(3,8) là ta gọi hàm và đưa vào hai số 3 và 8, dữ liệu đưa vào hợp lệ và nó sẽ thực hiện như ta mong muốn. Nhưng nếu
    tinhtong(3,"a") là hỏng kẹo ngay "a" không phải là số!
    Nhưng nếu: tinhtong(3,x) trong đó x là một biến mang giá trị kiểu số nguyên (int) thì hoàn toàn ok. Chỉ cần đúng kiểu là ok!

    main() cũng là một hàm. Nó đặc biệt hơn các hàm khác, nếu như các hàm khác chỉ được thực thi khi có lời gọi đến nó thì hàm main() được thực thi ngay khi chạy trương trình. main mà, chương trình chính :)). Trong hàm có thể gọi hàm nhưng phải tuân theo quy tắc hàm A gọi hàm B thì hàm B không được gọi lại hàm A dù trực tiếp hay gián tiếp!

    Các hàm phải được định nghĩa riêng rẽ với nhau không được giao nhau, hoặc lồng nhau. Ta không thể viết nội dung của hàm tinhtong() trong thân của hàm main() được.

    Trong bài viết bạn có thể giải thích trước CNTT = Công nghệ thông tin ngay đầu bài viết hoặc là có thể giải thích CNTT = Công nghệ thông tin ở cuối bài viết nhưng nếu làm thế thì ở đầu bài viết bạn phải thông báo là trong bài của tôi có sử dụng từ viết tắt là CNTT đấy. Nếu một hàm viết trước hàm main() thì ta có thể sử dung bình thường. Nhưng nếu ta định nghĩa hàm đó sau hàm main thì ta phải "đăng kí sử dụng" nó như thế này:

    void tinhtong(int a,int b); //<--- Đăng kí sử dụng có dấu ";"
    void main()
    {
    int a,b;
    tinhtong(a,b);
    }

    void tinhtong(int a,int b) //<-- định nghĩ phía dưới không có dấu ";"
    {
    return a+b;
    }

    Bạn nên viết hàm main() ở trên đầu chương trình vì ta phải theo dõi đến hàm main() nhiều, nếu để nó ở dưới cùng hoặc ở đâu đó thì bạn sẽ khó khăn khi tìm nó!
     

Chia sẻ trang này