cpp כיצד להשוות למפות


תשובה 1:

מתמטית, מפה היא מודל שלוקח מפתח ומגיב עם ערך. סט הוא מקרה מיוחד של מפה שהמפתח זהה לערך שהוא ממפה אליו. מושג זה משתרע על יישום C ++ של שני האובייקטים הללו.

מתי std :: map שימושי: שקול מסד נתונים המאחסן חשבונות משתמש, נניח שהם חשבונות נטפליקס. המפה המייצגת טבלה זו של משתמשי נטפליקס עשויה לקבל מזהה משתמש ולהחזיר את אובייקט המשתמש הרלוונטי למספר זהות זה. לאחר מכן נוכל להשתמש במזהה כדי לאחזר את חשבון המשתמש בזמן O (1) על ידי כיבוי מזהה המשתמש הייחודי לחשבון, וכדי לחפש חשבון כל מה שתצטרך הוא המזהה על מנת לאחזר את כל נתוני המשתמש הללו.

האם נוכל לעשות זאת עם std :: set? כיצד נוכל ליישם דוגמה קודמת זו עם סט? אנו יכולים להוסיף חשבונות משתמשים בקבוצת ה- std :: שלנו, אך כאשר אנו מעוניינים לחפש חשבון משתמש אנו נזדקק לחשבון המשתמש כולו על מנת לבצע חיפוש עבור רשומת המשתמש שלנו. חכה רגע, אם כבר יש לנו את פרטי חשבון המשתמש, למה שנצטרך לחפש אותו? מה גם אם יש לנו רק את מספר זיהוי המשתמש, לא נוכל יותר לאחזר את החשבון בזמן O (1), עלינו לחזור על הטבלה כולה כדי למצוא את החשבון שתואם וזה יהיה O (N).

מתי אולי תרצה להשתמש ב- std :: map לעומת מתי כדאי לך להשתמש ב- std :: map עבור פרימיטיביים? שקול מבנה שנועד לאחסן את כל המספרים הראשוניים תחת ערך שרירותי כלשהו. אם אנחנו פשוט רוצים לדעת אם מספר הוא חבר בקבוצת הראשונים אז std :: set הגיוני, ייתכן שנרצה לבדוק אם מספר שלם שרירותי הערך 'k' קיים במערך שלנו ואנחנו עשויים להיות מודאגים מכל מושג של אינדקס או מפתח. עם זאת, אם אנו מעוניינים ברצף הראשוני, אולי נרצה זיווג של ערך מפתח. אולי נרצה לדגם את הרצף p = {2, 3, 5, 7, 11, ...} ואנחנו רוצים לדעת אם p [j] = k עבור ערכים שרירותיים מסוימים של j & k. במקרה האחרון, ייתכן שנרצה לשקול את std :: map (אם כי גם std :: וקטור עשוי להיות בחירה טובה).

אז בקיצור:

  1. מבנה נתונים מוגדר הוא סוג מיוחד של מבנה נתוני מפות שבו ערך == ערך, והגדרות C ++ STL משקפות מושג זה
  2. std :: map מאשר std :: set בדרך כלל שימושי יותר מכיוון ש- std :: map מספק חיפוש מהיר על ידי מקש לערכים מצטברים (אובייקטים שלמים ולא פרימיטיביים).
  3. std :: set הוא לעתים קרובות שימושי יותר לפרימיטיבים שכן מיפוי ערך פרימיטיבי k-> k הוא שרירותי למדי

תשובה 2:

רבות מהתשובות אינן נוגעות בשינוי יישום המפה והגדרת מכולות ל- C ++ 17, גם כאשר הן רלוונטיות, לכן אעסוק בכך באופן בלעדי.

כיצד ניתן להעביר צומת ממכולה אחת לאחרת?

כיצד ניתן לשנות את מפתח צומת המפה?

אם הכנסת נתונים מטלטלים אך לא ניתנים להעתקה במפה או בערכה, כיצד תוכל להחזיר אותם שוב?

כל אלה נענו ב- C ++ 17 על ידי תוספת של מבנה נתונים אטום חדש ... ידית הצומת ... ושתי פונקציות חבר חדשות לכל קבוצה או מיכל מפה שעובדות עם ידיות צומת ... תמצית, המוציאה צומת ממפה או מוגדר לידית הצומת, ועומס חדש של הוספה, שלוקח צומת מידית הצומת ומכניס אותו למפה או לסט. יש גם שיטת נוחות חדשה, מיזוג, המעבירה את כל הצמתים שאינם כפולים במפה אחת או מוגדרת למערכת אחרת.

ידית צומת (C ++ 17)

לידית הצומת יש מספר מאפיינים. בבעלותו צומת חולץ בדיוק באותו אופן ש- std :: unique_ptr עושה וכך גם ניתן למטלטל אך לא ניתן להעתקה. אם ידית צומת מחזיקה בצומת כאשר הוא נהרס, הצומת נהרס וממוקד ... מה שאומר שהוא צריך שיהיה לו גם עותק של ההקצאה המשמש במיכל שלו כדי לבצע מיקום. המשמעות היא שהמקצים המשמשים בשני מכולות חייבים להשוות שווה (אופרטור == מחזיר נכון) כדי שיעביר צומת ממיכל אחד למשנהו. כל מחלקי ברירת המחדל משווים שווים, כך שלרוב זו לא בעיה.

בעוד שצומת נמצא בבעלות ידית צומת nh, ניתן לנתח אותו בדרכים שאינן אפשריות בזמן שהוא נמצא במפה או בערכה. לדוגמה, צומת מפה שחולץ יכול לשנות את המפתח שלו על ידי הקצאה ל- nh.key () ולהעביר ערך ממופה שאינו ניתן להעתקה באמצעות std :: move (nh.mapped ()). צומת קבוצה שחולצה יכול להעביר ערך שאינו ניתן להעתקה באמצעות std :: move (nh.value ()).


תשובה 3:

נכון לעכשיו, C ++ מציע 8 רגילים

מכולות אסוציאטיביות

במרחב זה:

  • std :: סט
  • std :: multiset
  • std :: unordered_set
  • std :: unordered_multiset
  • std :: מפה
  • std :: multimap
  • std :: un_orded_map
  • std :: unolded_multimap

ייתכן שתבחין שיש כאן 3 צירים של וריאציה:

  • להגדיר מול מפה.
  • הורה לעומת לא מסודר.
  • מפתח ייחודי מול מולטי מפתח.

שאלת לגבי סט מול מפה; עם זאת, כדאי לדעת כיצד לבחור בין כל 8 השילובים.

להגדיר מול מפה

סט מכיל סט מקשים. באפשרותך להכניס ולהסיר מפתחות מהסט, לבדוק אם המפתח קיים בערכה ולחזור על ערכת כל המקשים. ברגע שמכניסים מפתח לסט, המפתח אינו משתנה. אינך יכול לשנות מפתח לאחר הכנסתו. במקום זאת, עליך למחוק אותו ולהכניס את המפתח החדש אם ברצונך לשנות מפתח קיים.

מפה משייכת ערך לכל מקש. ערכים יכולים להיות סוג מובהק מהמפתח עצמו. בדרך כלל, גם ערכים ניתנים לשינוי. אני יכול לחפש ערך לפי המפתח שלו ולשנות את הערך ברגע שאמצא אותו.

אתה רוצה להשתמש בסט כאשר אתה מודאג רק ממערכת המפתחות שיש לך. אתה רוצה להשתמש במפה כשאתה עוסק במעקב אחר חבורה של ערכים שקשורים אליהם מפתחות.

לדוגמא, נניח שרציתי לעקוב אחר כל האנשים שנכחו בפגישה. ערכה עשויה להתאים לכך. כל משתתף הוא חבר בערכה, ואני יכול לחזור על כל חברי הסט לייצר רשימת משתתפים.

נניח שהפגישה שלי מסודרת, ואני רוצה לעקוב אחר העדפות הארוחות של כל האנשים שמשתתפים בפגישה שלי. עכשיו אני רוצה מפת משתתפים לפי העדפת הארוחות. המפתח במקרה זה הוא המשתתף, והערך הוא העדפת הארוחה. באפשרותך לשנות את העדפות הארוחות של כל משתתף מבלי לשנות את המשתתף עצמו. (זה פחות מביך ככה ...)

הורה לעומת לא מסודר

המכולות האסוציאטיביות בלי

לא מסודר

בהצעת השם

O (\ lg n)

זמן גישה. הם דורשים מפתחות שכן

ניתן להשוות

ו

הוזמן חלש קפדני.

הם בדרך כלל בנויים מעצי חיפוש בינאריים מאוזנים. אם אתה חוזר על כל האלמנטים, תבקר במקשים בסדר שלא יורד. (או הזמנה שאינה הולכת וגדלה, אם אתה משתמש באיטרטורים הפוכים)

המכולות האסוציאטיביות ללא סדר מסודרות בשם מציעות זמן גישה O (1) מופחת, בתנאי שתוכל לבנות פונקציית hash O (1) עבור המפתח שלך. באופן ידוע, אלה ידועים כטבלאות hash. אתה זקוק לפונקציית גיבוב יעילה כדי שהמכולות הלא מסודרות יעבדו ביעילות. אם תבצע איטרציה על כל האלמנטים, תבקר במפתחות בסדר שרירותי.

מתי כדאי להשתמש בהזמנה לעומת לא מסודרת? זה תלוי בכמה דברים:

  • האם אתה צריך לבקר בכל המקשים בסדר דטרמיניסטי לעיתים קרובות? אם כן, מיכל שהוזמן עשוי להיות בחירה סבירה.
  • האם ההשוואה מהירה או איטית יותר מאשר hashing? אם זה הרבה יותר מהיר, ההזמנה עשויה להיות טובה יותר. אם זה הרבה יותר איטי, לא מסודר יכול להיות מהיר יותר.
  • האם אתה יודע את הגודל הכולל המשוער של המכולה מראש? שינוי גודל מכולה לא מסודר יכול להיות יקר, בעוד שהכניסה למיכל שהוזמן אינה נוטה לנדנדות ביצועים פרועות.
  • איזה טביעת רגל זיכרון אתה יכול לסבול? מכולות לא מסודרות נוטות לסחור לפי מהירות.

אם אתה כותב את הקוד שלך בזהירות, אתה יכול לנסות לעבור בין מכולות שהוזמנו ולא מסודרים למבחן ביצועים שמניב ביצועים טובים יותר עבור עומס העבודה הספציפי שלך.

יישום אחד שכתבתי הסתיים בתערובת מעניינת של מכולות שהוזמנו ולא הוסדרו על סמך ביצוע ביצועים כאלה. הייתי קצת מופתע אילו מכולות זכו היכן וכיצד זה השתנה כששיניתי את מאפייני המפתחות. בפרט, מעבר מ- std :: מחרוזת לטבלת מחרוזות באינדקס של מספרים שלמים שינה את עלות פונקציות הגיבוב באופן ניכר.

מפתח ייחודי מול רב מקשים

המכולות האסוציאטיביות ללא רב בשם מאפשרות רק מופע יחיד של כל מפתח במיכל. כלומר, כל מפתח חייב להיות ייחודי. זה מספק סמנטיקה דומה למערך 1-D, כאשר כל אינדקס מכיל אלמנט אחד. הכנסת מפתח שכבר קיים במכולה היא שגיאה הגיונית.

המכולות האסוציאטיביות עם רב בשם מאפשרות מספר מופעים של כל מפתח. אתה יכול להכניס כל מקש כמה פעמים שתרצה. המקשים החוזרים נשמרים בסדר הכניסה.

הערה: זה חשוב אפילו עבור רב קבוצה שכן קריטריוני ההשוואה מבדילים בין שווה ערך לשווה. שני מקשים שווים אם אף אחד מהם לא משווה פחות מהשני; עם זאת, פונקציית ההשוואה אינה נדרשת לקחת בחשבון את כל השדות של אובייקט המפתח.

באיזה מהם כדאי לבחור? זה באמת תלוי בבעיה שאתה מנסה לפתור. מבחינה אנקדוטית, לעתים רחוקות הייתי זקוק למולטי סטים או מולטימפים.

אם אתה צריך לעקוב אחר כל המקרים של 'מקש' שאתה רואה, בין אם חלקם משתווים כשווים ובין אם לאו, הרי שמערכת רב-ממדית או רב-ממפ היא הבחירה הנכונה. אחרת, אתה כנראה רוצה את ערכות או מפות שאינן מרובות.

שימוש מעניין אחד עבור std :: multiset או std :: multimap הוא כתור עדיפות. השתמש בעדיפות כמפתח. האלמנט שהוחזר על ידי begin () הוא פריט העדיפות הגבוהה ביותר שלך. רשימת הפריטים נשמרת לפי סדר מיון, לכן בהינתן איטרטור שמצביע על פריט, תוכלו לקבוע במהירות מה בדיוק לפניו ואחריו. בפרט, אם עדיפות מיוצגת בפועל על ידי זמן - כלומר תור עדיפות זה הוא למעשה תור אירועים שהוזמן בזמן - אז אתה יכול לקבוע בזול אילו אירועים מתוזמנים בסמוך לזמן מסוים.

פעולה זו פועלת רק עם המולטי סט שהוזמן ומולטימפה שהוזמנה.

std :: prior_queue

יכול להיות בחירה טובה יותר אם אתה רק זקוק לגישה מהירה לפריט בעדיפות הגבוהה ביותר ולא תיהנה מאופי מלא של רב-מערכה או רב-מיפוי. (לִרְאוֹת

std :: prior_queue

לפרטים נוספים.)


תשובה 4:

ובכן אני יכול לענות על זה.

מפות

מפות דורשות מפתחות. לכל מפתח יש לך סוג / ים מסוימים של ערך / ים.

כעת, מפתח יכול להיות כל דבר, מספר שלם, מחרוזת או אפילו אובייקט (המסופק עם פונקציונליות השוואה נוספת). כך יכולים להיות הערכים.

תסתכל על זה:

מַפָּה M; // מפתח שלם - ערך שלםM [3] = 2;מַפָּה S; // מפתח מחרוזת - ערך שלםS ["אהר"] = 26;

זה מרתק.

נניח שאתה רוצה לאחסן את ימי ההולדת של חבריך. אתה פשוט מכריז על מפה ולאחסן את שמותיהם ותאריכי הלידה שלהם רק על ידי ביצוע מטלה פשוטה. זה כמו מילון בפייתון.

סטים

זה לא המקרה של סטים. סטים אינם זקוקים לזיווג (מפתח, ערך). הם פשוט מכילים כל סוג הערכים (כמובן עם פונקציות השוואה או העמסת יתר על המפעיל בעת הצורך) שתרצו שיכילו. לדוגמה:

מַעֲרֶכֶת S;סינסרט (13);מַעֲרֶכֶת T;סינסרט ("אהר");מַעֲרֶכֶת איקס;S.insert (yourObject);

מנקודת מבט הביצועים יש להם קווי דמיון. חיפוש, הכנסה, מחיקה וכו 'הם לפי סדר

O (logn)

בשניהם (תודה

עץ שחור אדום

הדבר שפחדת ממנו בקורס מבנה הנתונים שלך: P). אך בשל הבדלי היישום והשימוש, יכולות להיות תקורות מסוימות.

הערה נוספת:

אם תבצע תצפית, תגלה שמבחינה בסיסית מבנית, קבוצות ומפות שונים. אז השאלה ששאלת יכולה להיות קצת יותר מעניינת אם אתה חושב על זה בצורה שבה אתה יכול להשתמש בערכות כחלופה של מפות ולהיפך.

זה יכול להוביל אותנו לשאלה מעניינת: מה ההבדל בין סט > ומפה ? זו שאלה די תקפה מכיוון שבתרחיש זה, אתה יכול לחשוב על האלמנט הראשון של הצמד בערכה המקבילה למפתח במפה!

לדוגמה:

מַפָּה M;מינסרט ({"מוטה", 13});מַעֲרֶכֶת > S;סינסרט ({"מוטה", 13});

אתה יכול לראות שהסט שנכתב לעיל יכול להיות חלופי פוטנציאלי למפה.

אז האם הם שווים? ובכן לא.

ראשית, המפה אינה יכולה להכיל מספר שלם שונה עבור אותו מפתח כפי שהכרזנו לעיל. אבל סט יכול.

כך,

מינסרט ({"אהר", 13)};סינסרט ({"אהר", 13});מינסרט ({"אהר", 26});סינסרט ({"אהר", 26});

הופך את גודל הסט לשווה ל- 2 אך עבור המפה הוא 1.

שנית, עליכם כבר לדעת כי מכולות C ++ אלה משתמשות באיטטורים המשמשים לציון אלמנטים במיכלים אלה. כדי לחשוב את זה בפשטות, איטרטורים הם מה שאתה צריך כדי לגשת לנתונים במכולות אלה.

עכשיו תסתכל על זה:

מַעֲרֶכֶת > S;סינסרט ({"אהר", 26});auto it = S.begin (); // זה עכשיו איטרטור עבור ("אהר", 26)

מסיבה כלשהי, אתה מתכוון לשנות את הערך של הזוג המתאים שחוזר על ידו מ- 26 ל- 13. אתה מנסה זאת:

it-> second = 13;

אממ ... לא. אתה לא יכול לעשות את זה.

הסיבה מסובכת במקצת. במילים פשוטות, האיטרטורים עבור ערכת C ++ הם כמו איטרטורים קבועים. אז אתה לא יכול פשוט לשנות את ערך הנתונים המתאים במקום. עליך למחוק אותו מהסט ולאחר מכן להוסיף את הערך החדש שלך, כך:

ס '(זה);זוג p = {"אהר", 13};סינסרט (עמ ');

: |

במקרה של מפות, זה תקף לחלוטין:

מַפָּה M;מינסרט ({"מוטה", 13});auto it = M.begin ();it-> second = 26;

אני מקווה שהכל בסדר. : פ

תודה שקראת.


תשובה 5:

מפה היא מבנה נתונים המשמש לחיפוש ערכים לפי מקשים, ואילו סט הוא רק אוסף ערכים.

מבחינת היישום, הם בדרך כלל לא מיושמים באופן שונה ושניהם משתמשים בדרך כלל בעצים אדומים-שחורים מתחת למכסה המנוע כדי להשיג מורכבות זמן לוגריתמית לרוב הפעולות. הבדל אחד, תלוי ביישומים, הוא שקבוצה תהיה עץ אדום-שחור של אלמנטים ואילו מפה תהיה עץ אדום-שחור של אלמנטים כפולים (מפתח, ערך) הממוינים לפי האלמנט הראשון (המפתח) ב כפולה.


תשובה 6:

מפה ממפה אובייקט אחד לאחר. סט הוא קבוצה מסודרת של חפצים. לעתים קרובות משתמשים במפה כדי לגשת לאובייקטים על ידי אינדקס בצורה כזו ש- objectMap [i] מכיל את האובייקט עם אינדקס i. ניתן להשתמש בערכה לאחסון אובייקטים, עם היתרון הנוסף שמערכת מזהה האם אובייקט כבר כלול בו ומאחסנת רק ישות אחת של האובייקטים. עם זאת, אתה יכול לגשת לאובייקטים בקבוצה רק על ידי איטרציה מעליה או קבלת האלמנט הראשון או האחרון של הסט.


תשובה 7:

std :: map הוא מערך אסוציאטיבי ומסודר. זה אומר שהיא מאחסנת זוגות ולפי המפתח, ייתכן שתגיע לערך. כמו כן, אתה עלול לחזור על ה זוגות והאיטרציה יבצעו על פי סדר טוב של המפתחות.

std :: set הוא אוסף ערכים בלבד. שוב אתה יכול לחזור על זה ושוב האיטרציה תעבור לפי סדר טוב של הערכים. אבל אין קשר כמו לעיל, אתה יכול רק לשאול שאלות כמו "האם הערך הזה נמצא בסט?" ולשם כך, אתה חייב להיות בעל הערך המדובר.