การเรียงลำดับเวกเตอร์ตามลำดับจากมากไปน้อยภายในสองช่วง


14

ว่าฉันมีเวกเตอร์จำนวนเต็ม:

std::vector<int> indices;
for (int i=0; i<15; i++) indices.push_back(i);

จากนั้นฉันเรียงตามลำดับจากมากไปน้อย:

sort(indices.begin(), indices.end(), [](int first, int second) -> bool{return indices[first] > indices[second];})
for (int i=0; i<15; i++) printf("%i\n", indices[i]);

สิ่งนี้สร้างสิ่งต่อไปนี้:

14
13
12
11
10
9
8
7
6
5
4
3
2
1
0

ตอนนี้ฉันต้องการให้หมายเลข 3, 4, 5 และ 6 ถูกย้ายไปยังจุดสิ้นสุดและเก็บลำดับจากมากไปน้อยสำหรับพวกเขา (โดยไม่ต้องใช้sortเป็นครั้งที่สอง) คือนี่คือสิ่งที่ฉันต้องการ:

14
13
12
11
10
9
8
7
2
1
0
6
5
4
3

ฉันจะปรับเปลี่ยนฟังก์ชันการเปรียบเทียบของstd::sortเพื่อให้บรรลุได้อย่างไร


4
return indices[first] > indices[second]คุณไม่หมายถึงreturn first < second;เหรอ
acraig5075

2
สำหรับการเรียงลำดับอย่างง่ายstd::greaterจาก<functional>สามารถใช้แทนแลมบ์ดาของคุณได้ สำหรับคำถามของคุณการเขียนตัวเปรียบเทียบแบบละเอียดมากขึ้นเพื่อให้แน่ใจว่าค่าของคุณเปรียบเทียบกับวิธีที่คุณต้องการอาจเป็นวิธีที่ง่ายที่สุดในการทำ
sweenish

4
@ acraig5075 return first > secondในลำดับถัดลงมามันควรจะเป็น
ks1322

1
@ acraig5075 ฉันรู้สึกเหมือนฉันหายไปบางสิ่งบางอย่างหรือคนที่ไม่ทราบความแตกต่างระหว่างน้อยไปหามากและจากมากไปน้อย ?
sweenish

3
บางทีคุณกำลังมองหามาตรฐาน :: หมุน ?
สุดยอด

คำตอบ:


8

ฟังก์ชั่นการเปรียบเทียบของคุณผิดตั้งแต่ค่าที่คุณได้รับfirstและเป็นองค์ประกอบของsecond std::vectorดังนั้นจึงไม่จำเป็นต้องใช้พวกเขาเป็นดัชนี ดังนั้นคุณต้องเปลี่ยน

return indices[first] > indices[second];

ถึง

return first > second;

ตอนนี้เกี่ยวกับปัญหาที่คุณพยายามแก้ไข ...

คุณสามารถแยก 3, 4, 5 และ 6 ออกจากการเปรียบเทียบกับองค์ประกอบอื่น ๆ และยังคงเปรียบเทียบกับแต่ละอื่น ๆ :

std::sort(
    indices.begin(), indices.end(),
    [](int first, int second) -> bool {
        bool first_special = first >= 3 && first <= 6;
        bool second_special = second >= 3 && second <= 6;
        if (first_special != second_special)
            return second_special;
        else
            return first > second;
    }
);

การสาธิต


@NutCracker ใช่ฉันเห็นด้วยว่ามันดีกว่าที่จะมีเกณฑ์สูงสุดก่อน
Heap Overflow

5

ฟังก์ชั่นจากห้องสมุดขั้นตอนวิธีการมาตรฐานเช่นiota, sort, find, rotateและcopyจะทำให้ชีวิตของคุณง่ายขึ้น ตัวอย่างของคุณลงมาที่:

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>


int main()
{
  std::vector<int> indices(15);
  std::iota(indices.begin(), indices.end(), 0);
  std::sort(indices.begin(), indices.end(), std::greater<>());

  auto a = std::find(indices.begin(), indices.end(), 6);
  auto b = std::find(indices.begin(), indices.end(), 3);
  std::rotate(a, b + 1, indices.end());

  std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, "\n"));
  return 0;
}

เอาท์พุท:

14
13
12
11
10
9
8
7
2
1
0
6
5
4
3


@TedLyngmo ในความคิดเห็นทำให้จุดดีว่าควร / ควรปรับปรุงด้วย:

auto a = std::lower_bound(indices.begin(), indices.end(), 6, std::greater<int>{});
auto b = a + 4;

auto b = a + 4;ผิด (หากคุณต้องการรักษาความสอดคล้องกับตัวอย่างก่อนหน้านี้) อาจเป็นauto b = a + 3;เพราะในการstd::rotateใช้งานของคุณb + 1
Biagio Festa

3

โซลูชันที่ 1

วิธีการตรงไปตรงมากับตัวเปรียบเทียบที่ไม่ใช่แบบเชิงเส้น

inline constexpr bool SpecialNumber(const int n) noexcept {
  return n < 7 && 2 < n;
}

void StrangeSortSol1(std::vector<int>* v) {
  std::sort(v->begin(), v->end(), [](const int a, const int b) noexcept {
    const bool aSpecial = SpecialNumber(a);
    const bool bSpecial = SpecialNumber(b);

    if (aSpecial && bSpecial) return b < a;
    if (aSpecial) return false;
    if (bSpecial) return true;
    return b < a;
  });
}

โซลูชันที่ 2

ใช้std::algorithms (พาร์ติชัน)!

inline constexpr bool SpecialNumber(const int n) noexcept {
  return n < 7 && 2 < n;
}

void StrangeSortSol2(std::vector<int>* v) {
  auto pivot = std::partition(v->begin(), v->end(), std::not_fn(SpecialNumber));
  std::sort(v->begin(), pivot, std::greater{});
  std::sort(pivot, v->end(), std::greater{});
}

ข้อควรพิจารณาด้านประสิทธิภาพ

อาจดูเหมือนว่าโซลูชันที่สองช้าลงเนื่องจากโอเวอร์เฮดของพาร์ติชัน อาจไม่ใช่เพราะแคชและการคาดคะเนพลาดสาขาในโปรเซสเซอร์ที่ทันสมัย

เกณฑ์มาตรฐาน


คอมไพเลอร์ที่ดีควรแปลงn <= 6 && 3 <= n เป็นสิ่งที่ดีที่สุดสำหรับซีพียูเป้าหมายดังนั้นคุณจะไม่ได้อะไรเลยโดยการแนะนำหมายเลข 2 และ 7 แต่อาจเกิดความสับสน - และเหตุใดจึงนำตัวชี้ไปยังเวกเตอร์แทนการอ้างอิง
Ted Lyngmo

อย่าใช้ `const int number 'เป็นฟังก์ชันอาร์กิวเมนต์
Antoine Morrier

1
@AntoineMorrier ทำไม
กองมากเกิน

@HeapOverflow เพราะมันเหมือนกันโดยไม่ต้องใช้ const :)
Antoine Morrier

@AntoineMorrier ฉันไม่คิดว่ามันจะเหมือนกัน ไม่constบอกผู้อ่านว่าฟังก์ชั่นไม่เปลี่ยนค่าใช่ไหม ในกรณีเฉพาะของสายการบินเดียวอาจมีความชัดเจน แต่โดยทั่วไปแล้วไม่ใช่
กองมากเกิน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.