2012-02-05 54 views
5

Tôi rất bối rốiC# con trỏ, vòng lặp và generics

Làm cách nào để sử dụng trình lặp trong C# như trình lặp C++? Tôi không thể tìm thấy một accessor Begin() hoặc End(), thậm chí tôi không thể tìm ra cách khai báo một iterator. Tôi đã đọc về Ienumerator. Mục tiêu của tôi là triển khai hàm Merge. Đây là một phần của hàm Merge được viết bằng C++. Chủ yếu, tôi đang tìm kiếm C# tương đương với những gì được hiển thị, ngoại trừ tôi sẽ sử dụng một loại tham chiếu chứ không phải là số nguyên.

void merge(vector<int>::iterator left, vector<int>::iterator right, vector<int>::iterator  leftEnd, vector<int>::iterator rightEnd, vector<int>::iterator full) 
{ 

    while(left != leftEnd && right!= rightEnd) //compare left and right until the end of the vector is reached 
    { 
     if(*right < *left)  //right < left so insert right to the output vector and advance the iterators 
     { 
      *full++ = *right++; 
     } 
     else     //left < right so insert left to the output vector and advance the iterators 
     { 
      *full++ = *left++; 
     } 
    } 

    while(left != leftEnd) //copy any remaining elements into the output from left 
    { 
     *full++ = *left++; 
    } 
} 

Ngoài ra, tôi nên sử dụng bộ sưu tập nào? (hiện tại tôi đang thử List<T>LinkedList<T>).

+0

Không phải bạn đang triển khai lại phương pháp [Enumerable.Concat (Of TSource)] (http://msdn.microsoft.com/en-us/library/bb302894.aspx)? –

+0

@Serge no, đây là phần hợp nhất của sắp xếp hợp nhất. Chú ý 'if (* right <* left)' – CodesInChaos

Trả lời

7

Có vẻ như bạn muốn một cái gì đó như:

bool leftValid = left.MoveNext(); 
bool rightValid = right.MoveNext(); 

while (leftValid && rightValid) 
{ 
    if (right.Current < left.Current) 
    { 
     full.Add(right.Current); 
     rightValid = right.MoveNext(); 
    } 
    else 
    { 
     full.Add(left.Current); 
     leftValid = left.MoveNext(); 
    } 
} 

while (leftValid) 
{ 
    full.Add(left.Current); 
    leftValid = left.MoveNext();  
} 

while (rightValid) 
{ 
    full.Add(right.Current); 
    rightValid = right.MoveNext();  
} 

Đây full sẽ cần phải có một số loại IList<T> - lặp .NET không cho phép bạn thay đổi các bộ sưu tập bên dưới.

Bạn không nên cố gắng viết mã "bắc cầu" để cho phép bạn sử dụng trình lặp .NET như C++; bạn nên bắt đầu suy nghĩ về các trình lặp .NET khi bạn đang sử dụng .NET.

Lưu ý rằng rất hiếm khi vượt qua trình vòng lặp xung quanh trong .NET. Nó sẽ tự nhiên hơn để làm phương pháp của bạn để IEnumerable<T> thông số, và làm điều gì đó như:

using (IEnumerable<T> leftIterator = leftSequence.GetEnumerator()) 
{ 
    using (IEnumerable<T> rightIterator = rightSequence.GetEnumerator()) 
    { 
     // Code as above, just using leftIterator and rightIterator 
     // instead of left and right 
    } 
} 
+1

Và lưu ý rằng 'full' không thể là một iterator vì .NET liệt kê là chỉ đọc. Bạn sẽ phải chuyển vào thứ gì đó như 'IList'. –

+0

@MattiVirkkunen: Thật vậy - sẽ lưu ý điều đó. –

+0

@CodeInChaos: Xin lỗi, vâng, tôi sẽ làm rõ một chút về sự bất biến. Tôi không chắc chắn những gì bạn có ý nghĩa về. NET không hỗ trợ tạo bản sao của iterators - bạn có thể tạo ra một phương pháp mà phải mất hai 'IEnumerator ' s và nó sẽ làm việc tốt. Nó sẽ có ý nghĩa hơn để có 'IEnumerable ', nhớ bạn. Tôi sẽ chỉnh sửa cho điều đó. –

2

Tôi nghĩ rằng bạn muốn GetEnumerator(), MoveNext(), và hiện tại.

Thông thường, bạn chỉ có thể sử dụng foreach để lặp lại, nhưng trường hợp của bạn là đặc biệt.

Nếu thực tế, thay vì sử dụng "đầy đủ", hãy tổ chức điều này dưới dạng khối lặp và hợp nhất hai bảng liệt kê một cách lười biếng.

IEnumerable<T> Merge<T>(IEnumerable<T> left, IEnumerable<T> right) 
{ 
    ... yield return Min<T>(left.Current, right.Current); .., 
} 
3

.net containers không hỗ trợ trình lặp kiểu C++. Điều duy nhất họ có là một

  • đơn giản iterator về phía trước gọi là IEnumerator<T>
  • mà không thể sửa đổi bộ sưu tập
  • không được truy cập ngẫu nhiên
  • không thể sao chép (một số bộ sưu tập có kiểu giá trị các trình lặp có thể được sao chép, nhưng đó là việc kinh doanh phức tạp và hiếm khi được sử dụng)
  • và trên hầu hết các bộ sưu tập cũng bị vô hiệu bất cứ khi nào bạn sửa đổi bộ sưu tập

Khá nhiều điều duy nhất họ có thể làm là được lặp lại trong một tuyên bố foreach.


Bạn có thể muốn xem giao diện IList<T> cho phép truy cập ngẫu nhiên nhưng chỉ được hỗ trợ trên các bộ sưu tập hỗ trợ lập chỉ mục nhanh. Trên bộ sưu tập như vậy, bạn có thể triển khai sắp xếp hợp nhất tại chỗ bằng cách sử dụng các chỉ mục.

void Merge<T>(IList<T> container,int left, int right, int leftEnd, int rightEnd, int full) 

và sau đó sử dụng container[left] thay vì *left.


Kết quả không may là bạn không thể thực hiện chức năng phân loại độc lập tại chỗ hiệu quả như C++.

+0

Nếu chúng ta định nghĩa trình vòng lặp như là một bộ xử lý bất khả tri chứa một container thuận tiện cho một bộ sưu tập giữ vị trí hiện tại và cho phép điều hướng, loại trình vòng lặp duy nhất .NET hỗ trợ chuyển tiếp trình đọc chỉ đọc. Đó là một điều đáng tiếc. Có rất nhiều cách sử dụng cho các trình vòng lặp truy cập hai chiều hoặc ngẫu nhiên trong nhiều thuật toán nontrivial. –

0

Bạn có thể sử dụng các mảng có kích thước cố định hoặc List<T>, còn được gọi là ArrayLists bằng các ngôn ngữ khác. Các mục của chúng có thể được truy cập thông qua một bộ chỉ mục (list[i]) và các mục có thể được nối thêm với list.Add(item);. Chúng tự động phát triển. Không thể truy cập LinkedLists qua trình lập chỉ mục và phải được duyệt qua.

Bạn sẽ tuyên bố phương pháp như thế này

void merge(IEnumerator<int> left, IEnumerator<int> right, 
      List<int> full) 
{ 
    // Jon Skeet's code goes here 
} 

Bạn có thể lấy một Enumerator như thế này

IEnumerable<int> intEnumerable = ...; 
IEnumerator<int> intEnumerator = intEnumerable.GetEnumerator(); 

IEnumerable<T> được thực hiện bởi hầu hết các loại bộ sưu tập chung. Các bộ sưu tập không chung chung thường thực hiện IEnumerable.

(Đã chỉnh sửa để trả lời nhận xét của CodeInChaos).

+0

Không có số đếm bạn có thể chuyển sang 'left' /' right'. Đó là các bản sao của các trình lặp lặp lại một phần. – CodesInChaos

+0

Tôi không nghĩ rằng chỉnh sửa của bạn giải quyết được sự cố. Các trình vòng lặp đó có thể trỏ đến các phần tử khác nhau trong cùng một vùng chứa. Hãy coi chúng là chỉ mục trong danh sách, nhưng làm việc trên các bộ sưu tập không hỗ trợ lập chỉ mục nhanh. – CodesInChaos

+0

Một 'IEnumerator '(không phải' IEnumerable '!) ** là ** một loại chỉ mục trong danh sách. 'left' và' right' có thể trỏ đến các vị trí khác nhau trong cùng một bộ sưu tập ngay bây giờ. (Tôi đã thay đổi loại của họ từ 'IEnumerable ' thành 'IEnumerator ') –

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