2012-01-14 49 views

Trả lời

21

số
C++ có nhưng nó hoạt động như c = a;a = b; b = c;
C++ được xây dựng trong chức năng trao đổi: swap(first,second);
Kiểm tra này: http://www.cplusplus.com/reference/algorithm/swap/

Bạn có thể sử dụng để trao đổi hai giá trị biến mà không sử dụng biến thứ ba:

a=a^b; 
b=a^b; 
a=b^a; 

Bạn cũng có thể kiểm tra điều này:

https://stackoverflow.com/questions/756750/swap-the-values-of-two-variables-without-using-third-variable

How to swap without a third variable?

+1

giải pháp với tổng và khác biệt cần tránh. Với các toán hạng của các kiểu đã ký, nó có thể tràn và các luồng tràn đã ký sẽ không được xác định trong C. – ouah

+0

yap .. bạn đã đúng. cảm ơn :) – Saif

7

Không có chức năng như trong tiêu chuẩn C.

(Trong C++ thì bạn phải std::swap().)


Có lẽ một macro từ this question có thể hữu ích cho bạn.

+0

nói riêng, hãy nhìn vào http://stackoverflow.com/a/3983089/48015 – Christoph

22

Tại sao bạn không muốn sử dụng biến thứ ba? Đó là cách nhanh nhất trên phần lớn các kiến ​​trúc.

Các XOR swap algorithm công trình mà không có một biến thứ ba, nhưng nó là vấn đề theo hai cách:

  1. Các biến phải phân biệt ví dụ: swap(&a, &a) sẽ không hoạt động.
  2. Nói chung sẽ chậm hơn.

Đôi khi nên sử dụng chuyển đổi XOR nếu sử dụng biến thứ ba sẽ làm cho ngăn xếp tràn, nhưng nhìn chung bạn không ở vị trí đó để thực hiện cuộc gọi đó.

Để trả lời câu hỏi của bạn trực tiếp, không có hàm hoán đổi nào trong tiêu chuẩn C, mặc dù nó sẽ không quan trọng để viết.

+0

lập trình gì trên không? –

+0

@delnan: Tôi không cố gắng cho rằng hiệu suất là quan trọng. Tất cả những gì tôi nói là không có lý do (bao gồm cả hiệu năng) không muốn biến thứ ba. –

+8

@delnan: 'int t = a; a = b; b = t; 'v.s. 'a^= b; b^= a; a^= b; '. Thời gian lãng phí này ở đâu? Và đó là những gì vũ trụ đang viết một trao đổi đáng kể góp phần vào thời gian nó sẽ đưa bạn để giải quyết một vấn đề? Đây phải là vấn đề lớn nhất mà tôi chưa từng thấy. –

0

std::swap vì nói chung nó phụ thuộc vào bộ xử lý của bạn, cho dù nó có hỗ trợ tạo hình hay không. có một hướng dẫn được gọi là "so sánh và trao đổi", nhưng nó chỉ hoạt động trên các loại phù hợp với một thanh ghi và được đảm bảo là nguyên tử. Có một triển khai thực hiện so sánh và hoán đổi (CAS) từ gcc nó được sử dụng để đồng bộ hóa việc triển khai luồng và mutex và có lẽ cách ngoài phạm vi cho mục đích của bạn, vì vậy tốt nhất là chỉ sử dụng biến tạm thời hoặc nếu bạn thực sự bị mắc kẹt với C bạn luôn có thể sử dụng một macro như thế này:

#define swap(a,b) a=a^b; \ 
        b=a^b; \ 
        a=b^a; 
+0

không chỉ có một thẻ C++ chỉ một phút trước? – Alex

+0

Tôi nghĩ rằng litb loại bỏ nó vì câu hỏi yêu cầu về C. –

+0

vĩ mô này nên tránh. Đây là hành vi không xác định trong C vì 'a' được sửa đổi hai lần giữa điểm trước đó và điểm tiếp theo. – ouah

8

Giả sử bạn muốn có một C solotion , không phải là C++ một, bạn có thể biến nó thành macro, ít nhất bằng cách sử dụng phần mở rộng GCC để có nó đủ chung, e

#define SWAP(x,y) do { \ 
    typeof(x) _x = x;  \ 
    typeof(y) _y = y;  \ 
    x = _y;    \ 
    y = _x;    \ 
} while(0) 

coi chừng các thủ thuật như lời gọi swap(t[i++],i); để tránh chúng, hãy sử dụng toán tử địa chỉ &.Và bạn sẽ sử dụng tạm thời tốt hơn (cho các số nguyên, có một thủ thuật nổi tiếng và vô dụng với độc quyền hoặc).

PS: Tôi đang sử dụng hai biến cục bộ _x_y (nhưng tôi chỉ có thể sử dụng một biến cục bộ) để dễ đọc hơn và cũng có thể cho phép tối ưu hóa nhiều hơn từ trình biên dịch.

+1

Lợi ích của việc sử dụng hai biến tạm thời, thay vì chỉ là một (ví dụ: 'typeof (x) _tmp = x; x = y; y = _tmp;'? – einpoklum

+1

Khả năng đọc tốt hơn và có lẽ dễ dàng hơn –

4

Không có hàm chuẩn trong C để hoán đổi hai biến.

Một vĩ mô có thể được viết theo cách này:

#define SWAP(T, a, b) do { T tmp = a; a = b; b = tmp; } while (0) 

và vĩ mô có thể được gọi theo cách này:

int a = 42; 
int b = 2718; 

SWAP(int, a, b); 

Một số giải pháp cho một văn bản macro SWAP nên tránh:

#define SWAP(a, b) do { a = b + a; b = a - b; a = a - b; } while (0) 

khi toán hạng là các loại đã ký, có thể xảy ra tràn và tràn đăng nhập là hành vi không xác định.

Cũng là một giải pháp cố gắng để tối ưu hóa các giải pháp XOR như thế này nên được tránh:

#define SWAP(a, b) (a ^= b ^= a ^=b) 

a được sửa đổi hai lần giữa trước và điểm chuỗi tiếp theo, vì vậy nó vi phạm trình tự chỉ quy tắc và là hành vi không xác định .

+0

Không phải @ BasileStarynkevitch [phiên bản] (http://stackoverflow.com/a/8862167/1593077) của macro SWAP thích hợp hơn? – einpoklum

+1

@einpoklum: Không, bởi vì không phải mọi trình biên dịch đều là GCC, vì vậy bạn không thể dựa vào phần mở rộng GCC như 'typeof (expr)' –

+1

Tôi đặc biệt thích sử dụng 'int' làm đối số đầu tiên của macro. Bây giờ chúng ta có thể xác nhận rằng chúng ta có các mẫu trong ngôn ngữ yêu dấu của chúng ta :-) – paxdiablo

1

Không có tích hợp chức năng hoán đổi nhưng bạn có thể thử này

a = a^b;

b = a^b;

a = b^a;

2

Vì bạn có thể sao chép bất kỳ đại diện đối tượng vào một mảng char unsigned trong C , macro sau cho phép bạn hoán đổi hai đối tượng:

#define SWAP(X,Y) \ 
    do { \ 
     unsigned char _buf[sizeof(*(X))]; \ 
     memmove(_buf, (X), sizeof(_buf)); \ 
     memmove((X), (Y), sizeof(_buf)); \ 
     memmove((Y), _buf, sizeof(_buf)); \ 
    } while (0) 

GCC thậm chí sẽ tạo mã tối ưu cho điều này trong một số trường hợp. Bạn có thể không giữ công việc của mình mặc dù ...

+0

* Any * hai đối tượng? Giống như ... 'int x; double y; 'chẳng hạn? :-) Có lẽ bạn có nghĩa là bất kỳ hai đối tượng _of cùng loại._ – paxdiablo

1

Có chức năng thư viện C++. Nó hoán đổi giá trị của hai biến số nguyên. Ví dụ, hoán đổi (x, y); sẽ hoán đổi các giá trị của biến x và y. Tương tự, trao đổi (mat [i] [j], mat [j] [i]); sẽ trao đổi hai giá trị trong ma trận mat, cụ thể là giá trị trong hàng i cột j và giá trị trong hàng j cột i.

+1

Một chức năng thư viện C++ không phải là một hàm C, cũng không phải là nó được xây dựng trong – Chris

0

Tôi tin rằng tôi đã đưa ra một chức năng loại bất khả tri để hoán đổi hai giá trị trong tiêu chuẩn C, mặc dù vì tôi khá mới với ngôn ngữ mà tôi có thể đã bỏ qua điều gì đó.Nó sử dụng các thuật toán XOR trao đổi, và tôi chắc chắn rằng nó có thể được tối ưu hóa hơn, nhưng nó hoạt động miễn là hai giá trị trỏ đến cùng một số byte, quy định bởi đối số thứ 3: sử dụng

void swapn(void *a, void *b, size_t n) { 
    if (a == b) { 
     return; 
    } 

    size_t i; 
    char *x = (char *)a, 
     *y = (char *)b; 

    for (i = 0; i < n; i++) { 
     *x ^= *y; 
     *y ^= *x; 
     *x ^= *y; 
     x++; 
     y++; 
    } 
} 

Ví dụ :

// swap two integers 
int x = 5, 
    y = 30; 

printf("%d\t%d\n", x, y); 

swapn(&x, &y, sizeof(int)); 

printf("%d\t%d\n\n", x, y); 

// swap two floats 
float a = 9.23f, 
    b = 6.83f; 

printf("%.2f\t%.2f\n", a, b); 

swapn(&a, &b, sizeof(float)); 

printf("%.2f\t%.2f\n\n", a, b); 

// swap two doubles 
double p = 4.7539, 
    q = 0.9841; 

printf("%.4f\t%.4f\n", p, q); 

swapn(&p, &q, sizeof(double)); 

printf("%.4f\t%.4f\n\n", p, q); 

// swap two chars 
char m = 'M', 
    n = 'n'; 

printf("%c\t%c\n", m, n); 

swapn(&m, &n, sizeof(char)); 

printf("%c\t%c\n\n", m, n); 

// swap two strings of equivalent length 
char s[] = "Hello", 
    t[] = "World"; 

printf("%s\t%s\n", s, t); 

swapn(s, t, sizeof(s)); 

printf("%s\t%s\n\n", s, t); 

Đầu ra là:

5 30 
30 5 

9.23 6.83 
6.83 9.23 

4.7539 0.9841 
0.9841 4.7539 

M n 
n M 

Hello World 
World Hello 
+0

Tôi khá chắc chắn ba cách xor-phân công là hành vi không xác định, kể từ nó gán cho '* x' hai lần không có điểm chuỗi ở giữa. Đó là dễ dàng cố định, nhưng tôi không thấy lý do tại sao người ta nên bận tâm với xor trao đổi anyway. Nó không nhanh hơn, nó không dễ dàng hơn, nó phá vỡ khi hai tham số bí danh, và trong việc thực hiện chung hai mươi dòng này, biến số phụ thậm chí còn không thực sự mã nhiều hơn nữa. Nhưng nó có vẻ khá loại agonistic, tôi sẽ cung cấp cho bạn điều đó. 'n' nên là' size_t'. – delnan

+0

@delnan Tôi đã xóa hành vi không xác định và thay đổi đối số thứ 3 thành loại size_t. Bạn có ý nghĩa gì khi "bí danh hai thông số"? Tôi tin rằng nó được xử lý bởi câu lệnh if ban đầu. –

Các vấn đề liên quan