طراحی سایت و برنامه نویسی

آموزش طراحی سایت و برنامه نویسی

طراحی سایت و برنامه نویسی

آموزش طراحی سایت و برنامه نویسی

ایجاد انیمیشن اسکرول در فلاتر (Flutter) — از صفر تا صد

در این مقاله نگاهی به شیوه ساخت انیمیشن‌های اسکرول سفارشی از صفر تا صد با استفاده از SDK فلاتر خواهیم داشت. فلاتر یک ابزار پرقدرت برای ایجاد اپلیکیشن‌های نیتیو موبایل است که به صورتی عالی اجرا می‌شوند و انعطاف‌پذیری خارق‌العاده‌ای در زمینه خلق تجربیات کاربری غنی فراهم می‌سازد.

انیمیشن اسکرول در فلات

اگر به محیط فلاتر دسترسی ندارید به صفحه نصب (+) آن بروید.

شروع

در دمویی که در این مقاله می‌خواهیم بسازیم یک پروژه پیش‌فرض با استفاده از دستور flutter create ایجاد می‌کنیم و تنها از کلاس‌هایی استفاده می‌کنیم که مستقیماً درون فلاتر وجود دارند و لذا نیاز به افزودن هیچ وابستگی به پروژه نداریم. در اغلب موارد، یک وظیفه (مانند انیمیشن سفارشی) می‌تواند مستقیماً و بدون نیاز به کتابخانه‌های اضافی اجرا شود.

ایده اصلی این اپلیکیشن نمونه، ایجاد یک نمای لیستی ساده با چند آیتم است و زمانی که این نما به سمت پایین اسکرول می‌شود، در پس‌زمینه یک چرخ‌دنده در جهت‌های ساعت‌گرد یا پادساعت‌گرد می‌چرخد. این کار با کمک گرفتن از کنترلر اسکرول روی نمای لیستی و ارسال یک پس‌زمینه انیمیشنی به آن صورت می‌گیرد که یک ویجت سفارشی می‌سازد که همگام با موقعیت اسکرول به چرخش درمی‌آید.

نقطه ورود اپلیکیشن

کار خود را با فایل اصلی اپلیکیشن یعنی lib/main.dart آغاز می‌کنیم:

در فایل main.dart، برخی دستورهای ایمپورت برای کامپوننت‌های زیر وجود دارند:

  • demo-card.dart – یک ویجت کارت از یک آیتم می‌سازد.
  • items.dart – کلاس آیتم را تعریف کرده و محتوایی برای اپلیکیشن دمو ایجاد می‌کند.
  • animated-bg.dart – ویجت پس‌زمینه انیمیشنی را می‌سازد.

کلاس اپلیکیشن اصلی (AnimationDemo) یک اپلیکیشن ابتدایی می‌سازد که ویجت صفحه اصلی پیش‌فرض (MyHomePage) را پوشش می‌دهد. در کلاس MyHomePage یک مشخصه به نام controller_ وجود دارد که به یک وهله جدید از کلاس ScrollController مقداردهی می‌شود تا در ادامه به هر دو کامپوننت AnimatedBackground و ListView ارسال شود. کامپوننت AnimatedBackground به چرخاندن چرخ رنده در پس‌زمینه می‌پردازد و ListView نیز لیست اسکرول شونده از آیتم‌های دمو را رندر می‌کند. یک مشخصه به نام cards_ نیز وجود دارد که با لیستی از اشیای Item آغاز می‌شود که از items.dart ایمپورت شده‌اند و لیستی از ویجت‌های DemoCard برای رندر شدن در ListView بازگشت می‌دهد.

کلاس Item

نخستین فایل ایمپورت شده که به بررسی آن می‌پردازیم فایل lib/items.dart است:

کلاس Item ساختمان داده‌ای را ارائه می‌کند که همراه با وهله‌ای از DemoCard ارسال می‌شود تا در ListView رندر شود. در این مورد چیز خاصی زیادی برای تنظیم به جز یک نام، توضیح (که در حال حاضر در دمو بی‌استفاده است)، رنگ و آیکون برای رندر شدن هر آیتم وجود ندارد. لیستی از اشیای آیتم‌ها به عنوان لیستی از محتوای ساده ارائه می‌شود که درون ListView رندر می‌شوند.

کلاس DemoCard

فایل بعدی که بررسی می‌کنیم lib/demo-card.dart نام دارد:

کلاس DemoCard در سازنده خود یک آیتم دریافت می‌کند و یک ویجت کارت بازگشت می‌دهد که عناصر Text و Icon را رندر می‌کند که به نمایش نام و آیکون تعریف‌شده برای هر آیتم می‌پردازند. برخی استایل‌بندی‌های ساده نیز با استفاده از Shadow ،TextStyle و RoundedRectangleBorder همراه با ارتفاع کارت (که روی 3 تنظیم‌شده) اعمال می‌شوند. ویجت‌های Column و Row برای گسترش عناصر فرزند روی کارت استفاده می‌شوند.

کلاس AnimatedBackground

ما بهترین بخش کار را برای انتها نگه داشته‌ایم. بنابراین در این بخش به بررسی فایل lib/animated-bg.dart می‌پردازیم:

در همان ابتدای فایل، کتابخانه dart:math ایمپورت شده تا به ثابت π دسترسی پیدا کنیم که برای اجرای محاسبات تبدیل چرخشی برای گردش چرخ‌دنده مورد نیاز است. سازنده کلاس AnimatedBackground یک مقدار ScrollController می‌گیرد که اقدام به اجرای چرخش می‌کند. مشخصه offset_ در صورتی که کنترلر کلاینت‌هایی داشته باشد یعنی کنترلر به درستی مقداردهی شده باشد و به یک عنصر اسکرول شنونده واقعی مانند ListView قلاب شده باشد یک آفست بازگشت می‌دهد و در غیر این صورت مقدار صفر بازمی‌گرداند. متد build یک AnimatedBuilder بازگشت می‌دهد که کنترلر را می‌گیرد و یک OverflowBox می‌سازد که همراستا با چرخ‌دنده و خارج از صفحه جای می‌گیرد.

مقادیر 4 و 3 موجب می‌شوند که چرخ‌دنده در گوشه پایین-چپ دستگاه تست که یک شبیه‌ساز آیفون XR است، قرار گیرند. در عمل مقادیر Alignment باید از مختصات عرض و ارتفاع صفحه دستگاه محاسبه شوند تا مقادیر دقیقی برای قرار گرفتن چرخ‌دنده در موقعیت مطلوب در هر دستگاه به دست آید. با این حال ما در این مثال تلاش کرده‌ایم همه چیز تا حد امکان ساده باشد.

آخرین بخش جایی است که خود انیمیشن در آن اتفاق می‌افتد و این همان متد استاتیک rotate در کلاس است. این کلاس یک مقدار angle و یک child می‌گیرد و فرزند به وسیله زاویه مورد نظر به چرخش درمی‌آید. در این دمو ما می‌خواهیم که چرخ‌دنده به آرامی حرکت کند و بیشتر به فیزیک واقعی شبیه باشد تا چرخش سریع دیوانه‌وار که در زمان تعیین مقدار چرخش 1:1 به دست می‌آید. همچنین می‌خواهیم چرخ‌دنده در جهت پادساعت‌گرد بچرخد، گرچه از نظر فیزیکی لیست را به حرکت درمی‌آورد بنابراین offset را در math.pi ضرب کرده و سپس حاصل‌ضرب را بر 1024- تقسیم می‌کنیم.

سخن پایانی

این مقاله و پروژه نمونه صرفاً برخی از قابلیت‌هایی که فلاتر برای ایجاد تجربیات کاربری متحرک سفارشی ارائه می‌کنند را نشان دادند. ما با استفاده از تنها چند کلاس ابتدایی و مسیر ساده، یک انیمیشن کامل داریم که یک عنصر کاملاً ملال‌آور مانند صفحه تنظیمات را به چیزی کاملاً جذاب تبدیل می‌کند.

این مفاهیم می‌توانند برای ایجاد «صفحه‌های آغازین» (splash screens)، انیمیشن‌های بارگذاری، گذار صفحه، جلوه‌های نوتیفیکیشن یا هر چیز دیگری مورد استفاده قرار گیرند. تقریباً هر چیزی که یک مقدار Double به عنوان آرگومان می‌گیرد می‌تواند انیمیت شود و در نتیجه پیاده‌سازی سرراستی از جلوه‌های مختلف مانند چرخش در این مثال به دست می‌آید. همچنین میزان شفافیت، موقعیت و بسیاری مشخصه‌های دیگر نیز قابل تنظیم هستند.

منبع: فرادرس

ساخت ویجت گفتگوی زنده با پشتیبانی در ری اکت (React) — از صفر تا صد

فتگوی زنده یک روش پشتیبانی از مشتری است که سابقه‌ای طولانی دارد. این روش سریع و کارآمد است چون در آن هر کارمند می‌تواند همزمان به مشتریان زیادی کمک بکند. بهترین نکته این است که می‌توان در طی فرایند خرید به سریع‌ترین روش ممکن به سؤال‌های مشتری پاسخ داد و بدین ترتیب احتمال خرید مشتری بالا‌تر می‌رود.

در این مقاله به روش یکپارچه‌سازی یک گفتگوی زنده در اپلیکیشن‌های React می‌پردازیم. قصد ما این است که شیوه یکپارچه قابلیت گفتگوی زنده در اپلیکیشن ری‌اکت را بدون نگرانی از نگهداری سرور گفتگو و معماری آن پیاده‌سازی کنیم. در ادامه تصویری از آن چه قصد داریم بسازیم را مشاهده می‌کنید.

گفتگوی زنده

ما برای راه‌اندازی بخش گفتگوی اپلیکیشن خود از خدمات CometChat Pro استفاده می‌کنیم. CometChat Pro یک API ارتباطی قدرتمند است که امکان افزودن قابلیت‌های گفتگو را به اپلیکیشن فراهم می‌سازد. این API با قابلیت یکپارچه‌سازی آسان و مستندات منظم به شما کمک می‌کند تا ویژگی گفتگوی زنده را با نوشتن چند خط کد به اپلیکیشن خود اضافه کنید. به این منظور ابتدا باید یک حساب رایگان در این وب‌سایت (+) بسازید.

ما در این راهنما علاوه بر CometChat از فناوری‌های زیر نیز استفاده خواهیم کرد:

  • Create React App
  • react-chat-widget
  • Express
  • Bootstrap
  • Axios
  • react-md (spinner component only)

پیشنهاد ما این است که تا انتهای این راهنما همراه باشید تا گام‌به‌گام اپلیکیشن مورد نظر خود را بسازیم، اما اگر بیش از این شتاب دارید، می‌توانید کد کامل این مقاله را در این صفحه گیت‌هاب (+) ملاحظه کنید.

ایجاد اپلیکیشن CometChat

چنان که پیش‌تر گفتیم برای گنجاندن قابلیت گفتگوی زنده در اپلیکیشن از CometChat استفاده می‌کنیم. با این وجود، پیش از یکپارچه‌سازی باید ابتدا اپلیکیشن CometChat را بسازیم.

برای ایجاد یک اپلیکیشن CometChat باید به داشبورد CometChat بروید و روی آیکون + کلیک کنید. ما اپلیکیشن خود را react-chat-widget می‌نامیم، اما شما می‌توانید اپلیکیشن خود را با هر نامی که دوست دارید ایجاد کنید.

ما دو نوع کاربر داریم که به گفتگوی ما اتصال می‌یابند. یک دسته مشتری‌هایی هستند که ویجت گفتگو را باز می‌کنند و دیگری کارمندان بخش پشتیبانی هستند که به گفتگو دسترسی می‌یابند و از طریق داشبورد به پرس‌وجوها پاسخ می‌دهند. به طور کلی «کاربر» مفهومی بنیادی در CometChat محسوب می‌شود.

از آنجا که ما احتمالاً مشتریان زیادی خواهیم داشت، برای هر مشتری که به گفتگو وصل می‌شود، باید به صورت دینامیک یک کاربر CometChat ایجاد کنیم. با این وجود از آنجا که تنها یک کارمند وجود خواهد داشت، می‌توانیم یک Agent را از پیش در داشبورد ایجاد کنیم.

به این منظور در داشبورد به برگه Users بروید و روی Create User کلیک کنید:

گفتگوی زنده

برای ID کاربر مقدار ecommerce-agent را وارد کنید و برای نام کارمند نیز مقدار Demo Agent را وارد کنید. اگر قصد دارید از مراحل این راهنما پیروی کنید، از همین نام‌ها استفاده کنید، چون در غیر این صورت در ادامه با مشکل مواجه خواهید شد. ID کاربر را یادداشت کنید، زیرا در ادامه به آن ارجاع خواهیم داد.

پیش از آن که از داشبورد خارج شوید و به کدنویسی بپردازید، باید یک کلید دسترسی کامل CometChat نیز بسازید. در همین صفحه روی برگه API Keys و سپس روی Create API Key کلیک کنید:

گفتگوی زندهگفتگوی زنده

ما کلید خود را react-chat-api نامیده‌ایم، اما نام آن اهمیت چندانی ندارد. کلید API و ID اپلیکیشن خود را نیز مانند ID کاربر در جایی یادداشت کنید، چون در ادامه لازم خواهد شد.

راه‌اندازی اکسپرس

در گام قبلی یک کلید دسترسی کامل ساختیم که می‌توانیم از آن برای ایجاد دینامیک CometChat استفاده کنیم. با این که می‌توانیم این کار را در سمت کلاینت نیز اجرا کنیم، اما معنی آن این خواهد بود که کلید دسترسی کامل خصوصی خود را در معرض دسترس عموم قرار می‌دهیم که کار نادرستی است. برای جلوگیری از این مشکل یک سرور اکسپرس می‌سازیم که شرایط زیر را داشته باشد:

  1. کاربر CometChat را با استفاده از کلید دسترسی کامل بسازد.
  2. توکن‌های احراز هویت را بازگشت دهد (در ادامه بیشتر توضیح خواهیم داد)
  3. لیستی از کاربران CometChat برای استفاده بعدی در داشبورد بازگشت دهد.

اینک نوبت آغاز کار است. ابتدا یک دایرکتوری خالی جدید برای اپلیکیشن اکسپرس خود ایجاد می‌کنیم و دستور npm init -y را اجرا می‌کنیم:

mkdir react-express-chat-widgetcd react-express-chat-widgetnpm init –y

سپس اکسپرس و axios را نصب می‌کنیم:

npm install express axios

سپس در فایلی به نام server.js کد زیر را وارد می‌کنیم:

در فایل فوق موارد زیر وجود دارند:

  • اطلاعات هویتی اپلیکیشن و ID کاربر پاسخگو که قبلاً ایجاد کردیم ذخیره می‌شوند.
  • UIRL مربوط به API-ی CometChat برای دسترسی راحت‌تر تعریف می‌شود.
  • یک شیء headers که با استفاده از appID و apiKey ایجاد می‌شود. ما این هدر را به همراه هر درخواست CometChat ارسال می‌کنیم.

در همین فایل اکنون یک مسیر تعریف می‌کنیم تا ایجاد کاربران جدید CometChat را مدیریت کنیم. برای ایجاد یک کاربر جدید باید یک درخواست POST را با UID و نام کاربر ارسال کنیم.

در این راهنما، نام یکسانی را برای همه مشتریان به صورت hard-code می‌نویسیم، یعنی همه مشتری‌ها را «customer» می‌نامیم، اما UID آن‌ها باید یکتا باشد. برای UID می‌توانیم از تابع POST برای ایجاد ID-های یکتا استفاده کنیم.

کد زیر را به فایل server.js اضافه کنید:

زمانی که این مسیر فراخوانی شود، اکسپرس کارهای زیر را انجام می‌دهد:

  • یک درخواست POST به آدرس https://api.cometchat.com/v1/users با headers صحیح و اطلاعاتی در مورد کاربر جدید ارسال می‌کند.
  • توکن احراز هویت را برای کاربر جدید واکشی می‌کند.
  • و در نهایت آن را به فراخواننده بازمی‌گرداند.

ما همچنین یک تابع به نام requestAuthToken می‌سازیم تا به واکشی کردن توکن احراز هویت کمک کند. سپس در همان فایل یک مسیر احراز هویت می‌سازیم که آن را برای ایجاد توکن جهت کاربران بازگشتی فراخوانی خواهیم کرد:

در نهایت یک تابع برای بازگشت لیستی از کاربران ایجاد کرده و agent یا همان کارمند پشتیبانی را از آن حذف می‌کنیم. ما این endpoint را متعاقباً از داشبورد فراخوانی می‌کنیم تا لیستی از کاربران را که agent می‌تواند با آن‌ها صحبت کند نمایش دهیم. البته کارمند ما نمی‌تواند با خودش صحبت کند و از این رو خودش را از لیست فیلتر می‌کنیم:

در انتهای فایل server.js، سرور را اجرا می‌کنیم:

اگر از ابتدای این مقاله با ما همگام بوده باشید، اینک فایل Server.js باید به صورت زیر در آمده باشد:

در یک پنجره ترمینال دستور node server.js را اجرا کنید و منتظر باشید تا پیامی به صورت زیر نمایش یابد:

Listening on port 5000

اکنون باید زمان مناسبی برای تست endpoint-ها به همراه curl یا Postman باشد تا مطمئن شویم که کار می‌کنند و سپس به بخش کدنویسی کلاینت بپردازیم.

راه‌اندازی اپلیکیشن React

درون دایرکتوری خود دستور npx create-react-app را اجرا کنید تا ساختار اولیه یک اپلیکیشن ری‌اکت ایجاد شود:

npx create-react-app client

ساختار پوشه شما اینک باید مانند زیر باشد:

|-- express-react-chat-widget |-- package-lock.json |-- package.json |-- server.js |-- client |--.gitignore |-- package-lock.json |-- package.json |-- public |-- src

زمانی که اپلیکیشن ری‌اکت آماده شد، به دایرکتوری client بروید و ماژول‌های زیر را نصب کنید:

cd clientnpm install @cometchat-pro/chat react-chat-widget react-router-dom bootstrap react-md-spinner

اپلیکیشن Create React برای bootstrap کردن یک اپلیکیشن ری‌اکت کاملاً مفید است، اما فایل‌های زیادی تولید می‌کند که مورد نیاز ما نیستند و این‌ها شامل فایل‌های تست و از این دست هستند. پیش از اقدام به کدنویسی، همه چیز را از دایرکتوری client/src حذف کنید تا از صفر کار خود را شروع کنیم. برای شروع یک فایل config.js با ID اپلیکیشن و UID کارمند در مسیر client/src/config.js با محتوای زیر بسازید:

این کد مبنایی است که می‌توان برای ارجاع به اطلاعات احراز هویت CometChat از هر کجا مورد استفاده قرار داد. با این که ما آن را کد مبنا می‌نامیم، اما این فرصت را نیز داریم که یک فایل index.css بسازیم:

ما این فایل را در ادامه از داشبورد مورد ارجاع قرار می‌دهیم. اکنون در فایل با نام index.js کد زیر را درج کنید:

در این کد ما Bootstrap ،CometChat و فایل پیکربندی را که پیش از مقداردهی اولیه CometChat و رندر کردن App ساخته‌ایم ایمپورت می‌کنیم. اگر در این راهنما با ما همگام بوده باشید، متوجه شده‌اید که ما هنوز App را تعریف نکرده‌ایم. بنابراین در این مرحله این کار را انجام می‌دهیم. در فایل به نام App.js کد زیر را درج کنید:

در این کد ما دو مسیر را تعریف کردیم:

  • مسیر / یا Customer home جهت برقراری اتصال با کارمند پشتیبانی است.
  • و مسیر agent/ یا Agent Dashboard برای دسترسی سریع و راحت به داشبورد تعریف شده است.

در ادامه ابتدا کامپوننت در دید مشتری را بررسی می‌کنیم. ما آن را کامپوننت کلاینت می‌نامیم.

ایجاد کامپوننت کلاینت

کامپوننت کلاینت ما دو مسئولیت عمده خواهد داشت:

  1. ایجاد یک کاربر CometChat جدید از طریق سرور Express در زمانی که نخستین مشتری وصل می‌شود.
  2. ارسال و دریافت پیام‌ها به صورت آنی.

یک فایل به نام Client.js بسازید و کد زیر را در آن درج کنید:

اگر فکر می‌کنید این کد حجم بالایی دارد جای نگرانی نیست چون در ادامه آن را جزء به جزء توضیح می‌دهیم.

تابع render به قدر کافی ساده است، در واقع وظیفه اصلی آن رندر کردن react-chat-widget است. بخش زیادی از کد اختصاص به مدیریت پیام جدید ارسالی از سوی مشتری در تابعی به نام handleNewUserMessage دارد.

به طور خلاصه، ابتدا باید بررسی کنیم که آیا UID مشتری در localStorage وجود دارد یا نه. اگر چنین باشد، از این UID برای لاگین کردن کاربر و ارسال پیام استفاده می‌کنیم. در غیر این صورت تابع ()createUser را فراخوانی می‌کنیم و از مقدار بازگشتی برای لاگین کردن کاربر استفاده می‌کنیم. این تابع createUser یک endpoint را فراخوانی می‌کند که قبلاً در همین راهنما تعریف کردیم.

در نهایت در یک تابع چرخه عمر ری‌اکت componentWillUnmount را فرا می‌خوانیم و به خاطر می‌سپاریم که شنونده پیام را حذف کنیم. پیش از ادامه باید به یک نکته کوچک اشاره کنیم. در کد فوق، به جای وارد کردن URL سرور و پورت آن (localhost:5000/users) یا چیزی مانند آن در فرانت‌اند، می‌توانیم یک گزینه proxy به فایل package.json اضافه کنیم. بدین ترتیب می‌توانیم به جای localhost:5000/users// صرفاً از /users استفاده کنیم:

"browserslist": [">0.2%"، "not dead"، "not ie <= 11"، "not op_mini all"]،"proxy": http://localhost:5000

در این مرحله اپلیکیشن مانند زیر خواهد بود:

گفتگوی زنده

چنان که مشاهده می‌کنید، می‌توان پیام‌ها را ارسال یا دریافت کرد، اما اگر صفحه را رفرش کنیم، پیام‌های گفتگو ناپدید می‌شوند و این خوب نیست.

برای حل این مشکل یک متد componentDidMount تنظیم می‌کنیم که به دنبال UID مشتری در localStorage می‌گردد، به طوری که وقتی مشتریان صفحه را رفرش بکنند، می‌توانند گفتگو را از همان جایی که مانده بود ادامه دهند.

زمانی که UID را پیدا کردیم، می‌توانیم از آن برای مقداردهی اولیه یک زنجیره از متدها جهت login ،fetch کردن پیام‌های قبلی و ایجاد listener برای پیام‌های ورودی استفاده کنیم.

اکنون اگر صفحه را رفرش کنیم، اپلیکیشن تلاش خواهد کرد در CometChat لاگین کند و پیام‌های قبلی را به صورت خودکار با گشتن به دنبال UID مشتری در localStorage بارگذاری کند و این وضعیت مناسبی محسوب می‌شود.

اما همچنان مشکل کوچکی وجود دارد. چنان که مشخص شد، هنوز راهی برای کارمند پشتیبانی وجود ندارد که به پیام مشتری پاسخ دهد. ما این مشکل را از طریق ساختن داشبورد کارمند حل می‌کنیم. در این حالت کارمند می‌تواند به پیام‌های گفتگو که از سوی مشتریان می‌رسند پاسخ دهد. بدن ترتیب کار ما در فایل Client.js به پایان می‌رسد و در ادامه به ساخت فایل Agent.js می‌پردازیم.

ایجاد کامپوننت agent

کارکرد اصلی داشبورد agent دریافت همه مشتریان از CometChat Pro و نمایش تمام پیام‌های ورودی از مشتریان جدید در لیست گفتگوی مشتریان کارمند است تا بتواند روی آن‌ها کلیک کرده و پاسخ دهد. در واقع کارکرد اصلی بسیار شبیه به کلاینت است.

گفتگوی زنده

هنگام استفاده از CometChat به‌راحتی می‌توان چندین کارمند ایجاد کرد، اما برای این که همه چیز ساده بماند و درگیر مدیریت کاربر نشویم، در این راهنما از یک کارمند (agent) استفاده می‌کنیم که قبلاً آن را ایجاد کرده‌ایم. یک کامپوننت به نام Agent.js ایجاد کنید و حالت اولیه آن را به صورت زیر تعیین کنید:

در همان فایل، یک متد به نام componentDidMount ایجاد کنید:

در کد فوق کارهای زیادی انجام می‌یابند. در ادامه آن‌ها را به اختصار مرور می‌کنیم.

  • ابتدا به صورت خودکار agent را لاگین کرده و همه کاربران گفتگوی مربوطه را از سرور واکشی می‌کنیم.
  • سپس یک شنونده پیام ورودی می‌سازیم. هر بار که یک پیام در گفتگوی منتخب دریافت می‌شود، آن را به «حالت گفتگو» (Chat State) ارسال می‌کنیم که به نوبه خود موجب به‌روزرسانی UI می‌شود.
  • اگر پیام ورودی از گفتگوی انتخاب شده کنونی نباشد، بررسی می‌کنیم که آیا پیام جدید از مشتری e ثبت نام کرده آمده است یا نه. اگر چنین نبود، مشتری جدید را به «حالت مشتری» ارسال می‌کنیم.

احتمالاً به خاطر دارید که API اکسپرس را قبلاً برای دریافت لیستی از کاربران ثبت نام کرده ساختیم. از این API برای تشکیل لیستی از کاربران در سمت چپ داشبورد استفاده می‌کنیم. این لیست را با استفاده از ترکیب کلاس‌های بوت‌استرپ و فایل index.css که قبلاً تعریف کردیم، در سمت چپ داشبورد قرار می‌دهیم.

سپس یک تابع رندر می‌سازیم. این تابع اینترفیس گفتگو را رندر می‌کند و آن را با استفاده از بوت‌استرپ استایل‌دهی می‌کند. برای این که خواندن کد آسان‌تر شود، CustomerList و ChatBox را در کامپوننت‌های خاص خود قرار می‌دهیم که می‌توانند در فایل یکسانی تعریف شوند:

کامپوننت Chatbox

کامپوننت CustomerList

بدین ترتیب مبنایی برای UI ایجاد می‌شود، اما هنوز امکان ارسال پیام وجود ندارد. برای ارسال پیام‌ها باید یک دستگیره برای مواردی که کارمند یک پیام جدید را تحویل می‌دهد داشته باشیم. شیوه ارسال پیام‌ها اینک باید برای شما روشن باشد، زیرا از همان فراخوانی sendMessage که در سمت کلاینت استفاده کردیم بهره بخواهیم گرفت.

همچنین می‌خواهیم کارمند را قادر سازیم تا سوابق پیام‌ها را مانند حالتی که برای مشتری ایجاد کردیم، ببیند:

به خاطر داشته باشید که شنونده پیام را در زمان حذف کامپوننت پاک کنید:

محصول نهایی به صورت زیر خواهد بود:

گفتگوی زنده

اگر کنجکاو هستید که کاربران Superhero از کجا می‌آیند باید اشاره کنیم که این کاربران به صورت خودکار از سوی CometChat Pro در زمان ایجاد اپلیکیشن جدید ایجاد می‌شوند. پیش از استفاده عملیاتی از اپلیکیشن حتماً آن‌ها را حذف کنید.

اکنون کارمند پشتیبانی و مشتریان آماده گفتگو با همدیگر هستند. شما می‌توانید Client Home و Agent Dashboard را در پنجره‌های جداگانه‌ای باز کرده و این موضوع را بررسی کنید.

سخن پایانی

بدین ترتیب ما موفق شدیم ویجت گفتگوی زنده کاملاً اختصاصی خود را برای اپلیکیشن React در زمانی بسیار کوتاه بسازیم. در واقع، CometChat Pro به ما امکان می‌دهد که پیام‌ها را با نوشتن تنها چند خط کد ارسال و دریافت کنیم. بدین ترتیب دیگر نیاز به راه‌اندازی سرور گفتگوی شخصی و معماری آن وجود ندارد. البته این سرویس قابلیت‌های بسیار بیشتری از ساخت یک ویجت گفتگو دارد که بررسی همه آن‌ها از حیطه این مقاله خارج است.


منبع: فرادرس

اشتراک گذاری کد بین اندروید و iOS با ++C — از صفر تا صد

در این مقاله به توضیح روش اشتراک گذاری کد بین سیستم‌های عامل اندروید و iOS با استفاده از کدنویسی در زبان ++C می‌پردازیم.

اشتراک کد

چرا باید کد را به اشتراک گذاشت؟

اغلب توسعه‌دهندگان حرفه‌ای علاقه‌مند هستند که اپلیکیشن‌های نیتیو بنویسند و به باور این دسته بهترین UX از طریق رابط کاربری روان و بومی به دست می‌آید. اگر چه غالباً ضروری است که لایه ارائه نیتیو باشد، به طور عکس منطق تجاری اپلیکیشن را می‌توان به اشتراک گذاشت. زمانی که منطق تجاری اپلیکیشن به اشتراک گذارده می‌شود، می‌توان کد آن را یک بار نوشت و از این رو هزینه نگهداری کاهش می‌یابد و امکان طراحی رفتار مشابهی بین سیستم‌های عامل اندروید و iOS پدید می‌آید.

در اغلب پروژه‌ها دست‌کم بخشی از کد هست که می‌توان بین سیستم‌های عامل مختلف به اشتراک گذاشت. این بخش‌ها شامل منطق پایگاه داده، اعتبارسنجی کاربر و نظایر آن می‌شود. در اغلب این موارد، از ++C به عنوان یک زبان مشترک استفاده می‌شود. در این مقاله، ما با روش انجام این کار و مزایا و معایب استفاده از ++C برای توسعه اپلیکیشن‌های موبایل آشنا می‌شویم.

++C روی موبایل

سیستم‌های عامل موبایل امروزه به دو دسته iOS و اندروید تقسیم می‌شوند.

iOS

++C در سیستم عامل iOS یک شهروند درجه یک محسوب می‌شود. اگر شما نیز این روزها همچنان به این زبان برنامه‌نویسی می‌کنید، می‌توانید به سادگی با تغییر دادن فایل منبع از پسوند m. به nm. شروع به کدنویسی برای این سیستم عامل بکنید. البته این تغییر برخی ترفندهای جالب دیگر را نیز در سوئیفت در اختیار ما قرار می‌دهد. در سوی دیگر سوئیفت هیچ همکاری متقابلی با ++C ندارد. شما می‌توانید تابع‌های C و ++C را به هم مرتبط کنید؛ اما باید از یک پوشش ++Objective-C برای عرضه کلاس‌ها بهره بگیرید.

اندروید

اندروید نیز با استفاده از کیت توسعه نیتیو (NDK) می‌تواند از ++C در مواردی که به کدهای با عملکرد بالا نیاز هست یا لازم است کتابخانه‌هایی بر مبنای کدهای موجود ساخته شود استفاده کند. اینترفیس نیتیو جاوا (JNI) شیوه تعامل بین این کد نیتیو و بایت‌کد نوشته شده در جاوا یا کاتلین را تعیین می‌کند. پس از راه‌اندازی زنجیره ابزار، این فرایند به سادگی تعریف کردن و استفاده از متدهای نیتیو در جاوا خواهد بود:

اعلان تابع در سمت پیاده‌سازی C نیز چنین است:

در روزهای آغازین اشتراک کد در ++C نوشتن چنین اعلان‌های رمزآلودی، بخشی جدایی‌ناپذیر از فرایند توسعه محسوب می‌شد. خوشبختانه در سال 2014، Dropbox ابزاری به نام Djinni را منتشر ساخت که می‌توانست هر دو اتصال Objective-C++ و JNI را تولید کند.

Djinni

Djinni از یک زبان تعریف اینترفیس (IDL) ساده برای توصیف اینترفیسی که از سوی ++C عرضه می‌شود، استفاده کرده است. این IDL از رکوردها برای شیءهای مقدار خالص داده و از اینترفیس‌ها برای اشیایی که در یکی از محیط‌های ++C یا Objective-C/Java پیاده‌سازی می‌شوند بهره می‌گیرد.

Djinni از انواع مختلفی از داده از enum، بولی، عدد، رشته تا آرایه و نگاشت برای تعریف اینترفیس برای هر نوع اشتراک کدبیس پشتیبانی می‌کند و امکان پیاده‌سازی انواع داده سفارشی را نیز در صورت نیاز دارد. برای کسب اطلاعات بیشتر در مورد آن می‌توانید به این صفحه (+) مراجعه کنید.

متأسفانه دراپ‌باکس اخیراً اعلام کرده است که نگهداری از Djinni را متوقف می‌کند. اما این پروژه به قدر کافی بالغ و پایدار است که بتوان بر مبنای آن کدنویسی کرد و تصور نمی‌شود در طی زمان معقولی در آینده مشکل چندانی پیش بیاید.

تنظیم Djinni

هر پروژه‌ای یک ریپازیتوری GIT دارد که شامل تعاریف اینترفیس و کد ++C اشتراکی است. متأسفانه Djinni تنها یک فایل IDL می‌پذیرد. از این رو باید برای هر IDL در ریپازیتوری یک فراخوانی به djinni/run داشته باشیم. در حال حاضر فرایند Make برای اندروید به صورت دستی آغاز می‌شود. روی iOS این فرایند به صورت یک Run Script Phase به فرایند build اضافه شده است.

روی هر دو پلتفرم پیاده‌سازی ++C به همراه فایل‌های تولید شده مستقیماً به پروژه اضافه می‌شوند. همچنین یک کتابخانه استاتیک ساخته می‌شود، اما افزودن همه چیز به یک پروژه موجب می‌شود که فرایند توسعه و دیباگ کردن به مقدار زیادی آسان‌تر شود. روی اندروید، CMakeList را راه‌اندازی می‌کنیم که شامل همه فایل‌ها در چند دایرکتوری است. اما روی iOS به صورت دستی فایل‌های جدید را اضافه می‌کنیم.

افزودن کد جدید ++C

در این بخش مراحلی را که برای افزودن یک قابلیت جدید به کدبیس اشتراکی نیاز داریم توضیح داده‌ایم. در این مثال، کار خود را از سمت Xcode/iOS آغاز می‌کنیم، اما شما می‌توانید کار خود را از سمت اندروید نیز شروع کنید. ما می‌خواهیم فاصله بین دو رشته را محاسبه کنیم. این مسئله به نام «فاصله لون‌اشتاین» (Levenshtein Distance) مشهور است.

تعریف اینترفیس

اشتراک کد

ابتدا باید یک فایل جدید IDL برای تعریف اینترفیس اضافه کنیم. Makefile ما انتظار دارد که یک فایل با پسوند.jinni دریافت کند. پیاده‌سازی آن کاملاً سرراست است. ما یک اینترفیس جدید تعریف می‌کنیم و c+ را نیز اضافه می‌کنیم تا به djinni اعلام کنیم که اینترفیس ++C را پیاده‌سازی خواهیم کرد. سپس یک متد استاتیک اضافه می‌کنیم که دو رشته را گرفته و یک عدد صحیح باز می‌گرداند.

تولید فایل‌ها

اشتراک کد

پس از افزودن یک فایل جدید IDL پروژه خود را یک بار build می‌کنیم تا فایل‌های bridging جدید تولید شوند. سپس آن‌ها را به صورت دستی به پروژه Xcode اضافه می‌کنیم. برای این که فایل‌ها در اختیار سوئیفت قرار گیرند، باید آن‌ها را به هدر bridging نیز اضافه کنیم. چنان که پیش‌تر اشاره شد، باید Make را به صورت دستی فراخوانی کنیم تا فایل‌ها را برای bridging مربوط به JNI اندروید تولید کند.

پیاده‌سازی ++C

در نهایت می‌توانیم شروع به پیاده‌سازی «منطق تجاری» (business logic) کوچک خود بکنیم. ابتدا یک فایل ++C می‌سازیم و آن را به پروژه Xcode اضافه می‌کنیم. در واقع ما صرفاً اعلان تابع را از هدر عمومی کپی کرده و به پیاده‌سازی حاصل از Rosettacode (+) اضافه کردیم.

استفاده در پروژه‌ها

کار به همین سادگی بود که شرح دادیم، ما فاصله را در ++C پیاده‌سازی کردیم و اینک می‌توان آن را در Objective-C ،Swift ،Java یا Kotlin استفاده کرد.

سخن پایانی

آیا ++C زبان مناسبی برای نوشتن یک پروژه اپلیکیشن موبایل محسوب می‌شود؟ پاسخ این است که اگر تمایل به نوشتن کد ++C داشته باشید چنین است و این تنها شرط لازم و کافی برای چنین کاری محسوب می‌شود. یک پیکربندی با سازماندهی مناسب از djinni بخش عمده‌ای از دشواری پل زدن بین سیستم‌های عامل را رفع می‌کند، اما موجب کاهش پیچیدگی نوشتن کدهای ++C نمی‌شود. وقتی به زبان‌های Objective-C ،Swift ،Java یا Kotlin کدنویسی می‌کنید، احتمال بروز باگ خطرناک در اپلیکیشن کم است، اما در زمان کدنویسی ++C چنین امری کاملاً محتمل است. در هر حال، اگر تیم شما از قبل تجربه‌ای در کدنویسی به زبان ++C دارد و آن را زبان مناسبی می‌داند، می‌توانید با استفاده از این زبان به شدت سریع و بالغ و دارای پشتیبانی مناسب اقدام به اشتراک کد بین پلتفرم‌های مختلف بکنید.

مزیت‌ها

  • هر دو پلتفرم اندروید و iOS خودشان بر مبنای ++C توسعه یافته‌اند و از این رو زبان رسمی آن‌ها است و کاملاً پشتیبانی می‌شود.
  • ++C سریع و بالغ است.
  • Djinni بخش عمده دشواری پل زدن را به خصوص از طریق JNI از میان برمی‌دارد.

معایب

  • یادگیری ++C دشوار است.
  • بروز خطا در ++C بسیار محتمل‌تر است.
  • برای تعریف اینترفیس‌ها به یک زبان سوم نیاز دارید.
  • متدهای بصری تولید شده به صورت خودکار، یک سطح غیرضروری از انتزاع محسوب می‌شوند.
  • پشتیبانی دیباگر به اندازه زبان‌های ابتدایی پلتفرم‌ها خوب نیست.
  • در نهایت با پیچیدگی‌های کدنویسی به زبان ++C روبرو خواهید بود.

در سال‌های اخیر بسیاری از اپلیکیشن‌های بزرگ از این تکنیک اشتراک کد از طریق ++C و Djinni استفاده کرده‌اند. این تکنیک امکان بهره‌برداری حداکثری از سخت‌افزار موجود، تکرارهای سریع بدون نگرانی از واگرایی و تمرکز روی نکته‌ای که برای همه توسعه‌دهندگان مهم است، یعنی ایجاد یک تجربه کاربری عالی را فراهم ساخته است.


منبع: فرادرس

مرتب سازی هیپ (Heap Sort) در جاوا — راهنمای جامع

در این راهنما با طرز کار مرتب‌سازی و روش پیاده‌سازی آن در جاوا آشنا می‌شویم. مرتب‌سازی هیپ یا Heap Sort چنان که از نامش برمی‌آید بر مبنای ساختمان داده هیپ اجرا می‌شود. برای درک صحیح هیپ ابتدا باید با ساختمان آن و روش پیاده‌سازی‌اش آشنا شویم.

ساختمان داده هیپ

هیپ یک ساختمان داده خاص مبتنی بر درخت است و از این رو هیپ را گره‌هایی تشکیل می‌دهند. ما عناصر هیپ را به این گره‌ها انتساب می‌دهیم. هر گره شامل دقیقاً یک عنصر است. ضمناً گره‌ها می‌توانند فرزندانی داشته باشند. اگر یک گره هیچ فرزندی نداشته باشد آن را برگ می‌نامیم. آنچه هیپ را خاص می‌سازد دو چیز است:

  1. مقدار هر گره باید کمتر یا مساوی مقادیر ذخیره شده در فرزندان آن باشد.
  2. هیپ یک درخت کامل است یعنی کمترین ارتفاع ممکن را دارد.

به دلیل قاعده اول فوق کمترین عنصر همواره در ریشه درخت قرار می‌گیرد. روش الزام این قواعد نیز به نوع پیاده‌سازی وابسته است. هیپ‌ها عموماً برای پیاده‌سازی صف‌های اولویت استفاده می‌شوند، زیرا هیپ یک پیاده‌سازی کاملاً کارآمد برای استخراج عنصر با کمترین (یا بیشترین) مقدار محسوب می‌شود.

انواع هیپ

هیپ گونه‌های بسیار مختلفی دارد که تنها تفاوت آن‌ها از نظر برخی جزییات پیاده‌سازی با هم متفاوت هستند. برای نمونه آن چه در بخش فوق توصیف کردیم، یک Min-Heap یا هرم کمینه است، زیرا مقدار والد همواره کمتر از فرزندانش است. به طور جایگزین می‌توان Max-Heap یا هرم بیشینه نیز داشت که در آن والد همواره بزرگ‌تر از فرزندانش است. از این رو بزرگ‌ترین عنصر در گره ریشه قرار خواهد داشت.

ما می‌توانیم از میان پیاده‌سازی‌های مختلف درخت یکی را برای هیپ انتخاب کنیم. سرراست‌ترین گزینه درخت دودویی است. در درخت دودویی هر گره می‌تواند حداکثر دو فرزند داشته باشد. ما آن‌ها را برگ چپ و برگ راست می‌نامیم. ساده‌ترین روش برای الزام به قاعده دوم بخش فوق استفاده از درخت دودویی کامل است. یک درخت دودویی کامل داری قواعد ساده‌ای به شرح زیر است:

  • اگر یک گره تنها یک فرزند داشته باشد، این گره باید برگ چپ باشد.
  • تنها گره سمت راست روی عمیق‌ترین سطح می‌تواند دقیقاً یک فرزند داشته باشد.
  • برگ‌ها می‌توانند صرفاً در عمیق‌ترین سطح باشند.

در مثال‌های زیر نمونه‌هایی از قواعد فوق را می‌بینید:

درخت‌های 1، 2، 4، 5 و 7 از قواعد فوق پیروی می‌کنند. درخت‌های 3 و 6 از قاعده 1 تخطی کرده‌اند. درخت‌های 8 و 9 از قاعده دوم تخطی کرده‌اند و درخت شماره 10 قاعده سوم را نقض می‌کند.

ما در این راهنما روی Min-Heap با پیاده‌سازی درخت دودویی متمرکز می‌شویم.

درج عناصر

ما باید همه عملیات را به ترتیبی پیاده‌سازی کنیم که هیپ بدون تغییر بماند. بدین ترتیب می‌توانیم هیپ را با استفاده از درج‌های مکرر بسازیم. بنابراین در ادامه روی یک عمل درج منفرد متمرکز می‌شویم:

  1. یک برگ جدید بسازید که سمت راست‌ترین جایگاه ممکن روی عمیق‌ترین سطح است و آیتم را در این گره ذخیره کنید.
  2. اگر این عنصر کمتر از والدینش باشد، جای آن‌ها را با هم عوض می‌کنیم.
  3. گام 2 را تا زمانی که عنصر کمتر از والدینش باشد و یا به ریشه جدید تبدیل شود ادامه می‌دهیم.

توجه کنید که گام 2 فوق، قاعده هیپ را نقض نمی‌کند، زیرا اگر مقدار یک گره را با مقدار کمتر عوض کنیم همچنان کمتر از فرزندانش خواهد بود.

در ادامه یک مثال عملی را بررسی می‌کنیم. فرض کنید می‌خواهیم مقدار 4 را در این هیپ درج کنیم:

نخستین گام این است که یک برگ جدید ایجاد می‌کنیم تا مقدار 4 را در آن وارد نماییم:

از آنجا که 4 کمتر از والد خود، 6 است، جای آن‌ها را با هم عوض می‌کنیم:

اکنون بررسی می‌کنیم که آیا 4 کمتر از والد خود است یا نه. از آنجا که والد آن 2 است، در این مرحله متوقف می‌شویم. هیپ همچنان معتبر است و ما مقدار 4 را درج کرده‌ایم.

اکنون تصور کنید می‌خواهیم مقدار 1 را در این هیپ درج کنیم:

ما باید جای 1 و 4 را تعویض کنیم:

اکنون باید جای 1 و 2 را عوض کنیم:

از آنجا که 1 به ریشه جدید تبدیل شده است در این مرحله متوقف می‌شویم.

پیاده‌سازی هیپ در جاوا

از آنجا که از درخت دودویی کامل استفاده می‌کنیم، می‌توانیم آن را با یک آرایه پیاده‌سازی کنیم. هر عنصر آرایه یک گره در درخت محسوب می‌شود. هر گره با اندیس‌های آرایه از چپ به راست و از بالا به پایین به روش زیر نشانه‌گذاری می‌شود:

تنها کاری که باید انجام دهیم، این است که دقت کنیم چه تعداد عنصر باید در درخت ذخیره کنیم. بدین ترتیب اندیس عنصر بعدی که می‌خواهیم درج کنیم، اندازه آرایه خواهد بود.

با این روش اندیس‌گذاری می‌توانیم اندیس گره‌های والد و فرزند را محاسبه کنیم:

  • والد:  2/  (index – 1)
  • فرزند چپ: 2index +2
  • فرزند راست:  2index + 2

از آنجا که نمی‌خواهیم دردسر تخصیص مجدد آرایه را داشته باشیم، آن پیاده‌سازی را با بهره‌گیری از ArrayList از آن چه که هست بازهم ساده‌تر می‌کنیم.

پیاده‌سازی یک درخت دودویی کامل چیزی مانند زیر است:

کد فوق تنها عنصر جدیدی به انتهای درخت اضافه می‌کند. از این رو باید عنصر جدید را در صورت لزوم به سمت بالا پیمایش کنیم. این کار را با کد زیر می‌توانیم انجام دهیم:

دقت داشته باشید که چون نیاز داریم عناصر را مقایسه کنیم، باید آن‌ها را با استفاده از java.util.Comparable پیاده‌سازی کنیم.

مرتب‌سازی هیپ

از آنجا که ریشه هیپ همواره شامل کوچک‌ترین عنصر است، ایده اصلی مرتب‌سازی هیپ کاملاً ساده است: گره‌های ریشه را تا زمانی که هیپ کاملاً خالی شود، حذف می‌کنیم. تنها کاری که باید انجام دهیم یک عملیات حذف است که هیپ را در حالت سازگار حفظ می‌کند. ما باید مطمئن شویم که ساختار درخت دودویی یا مشخصه هیپ نقض نمی‌شود.

برای این که ساختار حفظ شود نمی‌توانیم هیچ عنصری را به جز برگ منتهی‌الیه سمت راست حذف کنیم. بنابراین ایده کار این است که گره ریشه را حذف کنیم و برگ سمت راست را در گره ریشه ذخیره کنیم. اما این عملیات قطعاً مشخصه هیپ را نقض می‌کند. بنابراین اگر ریشه جدید بزرگ‌تر از هر یک از گره‌های فرزندش باشد، آن را با کمترین فرزندش عوض می‌کنیم. از آنجا که گره کوچک‌ترین فرزند، کوچک‌تر از همه گره‌های فرزند دیگر است، مشخصه هیپ نقض نمی‌شود.

این کار تعویض را تا زمانی که عنصر به یک برگ تبدیل شود و یا کمتر از همه فرزندانش باشد، ادامه می‌دهیم. برای مثال، در هیپ زیر می‌خواهیم ریشه را از درخت حذف کنیم:

ابتدا برگ آخر را در ریشه قرار می‌دهیم:

سپس از آنجا که بزرگ‌تر از هر دو فرزند خود است، آن را با کمترین فرزندش یعنی 2 عوض می‌کنیم:

4 کمتر از 6 است و بنابراین در این مرحله متوقف می‌شویم.

پیاده‌سازی مرتب‌سازی هیپ در جاوا

بر اساس همه آن چه تا به اینجا گفتیم، حذف کردن ریشه (popping) کاری مانند زیر است:

چنان که پیش‌تر گفتیم، مرتب‌سازی صرفاً به ایجاد هیپ و حذف کردن مکرر ریشه مربوط است:

کارکرد این الگوریتم را با تست زیر می‌توانیم بررسی کنیم:

توجه کنید که امکان ارائه یک پیاده‌سازی که مرتب‌سازی درجا انجام دهد نیز وجود دارد. این کار بدان معنی است که نتیجه را در همان آرایه‌ای که عناصر را در خود دارد ارائه کنیم. به علاوه در این روش به هیچ تخصیص حافظه آنی نیاز نداریم. با این حال، درک آن پیاده‌سازی کمی دشوارتر خواهد بود.

پیچیدگی زمانی

مرتب‌سازی هیپ دو مرحله کلیدی دارد که یک درج کردن عنصر و دیگری حذف گره ریشه است. هر دو مرحله دارای پیچیدگی زمانی (O(log n هستند. از آنجا که هر دو مرحله n بار تکرار می‌شوند، پیچیدگی مرتب‌سازی کلی برابر با (O(n log n خواهد بود.

دقت کنید که ما به هزینه تخصیص مجدد آرایه اشاره نکردیم، اما از آنجا که پیچیدگی آن (O(n است تأثیری روی پیچیدگی کلی نخواهد داشت. ضمناً چنان که پیش‌تر گفتیم، امکان پیاده‌سازی مرتب‌سازی به صورت درجا نیز وجود دارد. بدین ترتیب نیازی به تخصیص مجدد آرایه هم وجود نخواهد داشت. همچنین باید اشاره کنیم که در هیپ 50% از عناصر برگ هستند و 75% از آن‌ها عناصری هستند که در پایین‌ترین سطح قرار دارند. از این رو اغلب عملیات درج، به چیزی بیش از دو گام نیاز نخواهند داشت.

توجه داشته باشید که در داده‌های دنیای واقعی، الگوریتم Quicksort کارآمدتر از مرتب‌سازی هیپ است. نکته اینجا است که الگوریتم مرتب‌سازی هیپ همواره سناریوی بدترین حالت یعنی پیچیدگی زمانی (O(n log n را دارد.

سخن پایانی

در این راهنما، یک پیاده‌سازی از هیپ دودویی و مرتب‌سازی هیپ را مورد برسی قرار دادیم. با این که پیچیدگی زمانی آن در اغلب موارد (O(n log n است، اما بهترین الگوریتم در دنیای واقعی محسوب نمی‌شود.


منبع: فرادرس