ما در مقالات قبلی بلاگ کنکور کامپیوتر به بررسی لیست پیوندیلیست پیوندی چیست؟ آموزش لیست پیوندی ساده، دو طرفه و حلقویلیست پیوندی چیست؟ این صفحه عالی به آموزش لیست پیوندی ساده، دو طرفه و حلقوی با مثال پرداخته و پیاده سازی و عملیات مهم و کاربردهای لیست پیوندی را گفته است پرداختهایم. لیست پیوندی حلقوی نوعی از لیست پیوندی است که در آن، اولین و آخرین گره به یکدیگر متصل میشوند تا یک دایره یا حلقهحلقه در برنامه نویسی چیست؟ حلقه یا لوپ (Loop) چیست؟این مقاله عالی به زبان ساده و با استفاده از فیلم توضیح داده که حلقه در برنامه نویسی چیست، همچنین در خصوص حلقه یا لوپ (Loop) بی نهایت صحبت کرده است را تشکیل دهند. ما در این مقاله، به بررسی این نوع از لیست پیوندی میپردازیم. اساساً دو نوع لیست پیوندی حلقوی وجود دارد:
- لیست پیوندی حلقوی ساده: در این نوع، آخرین گره به گره اول به عنوان گره بعدی اشاره میکند.
- لیست پیوندی حلقوی دوطرفه: در این نوع، علاوه بر آخرین گره که آدرس اولین گره را ذخیره میکند، اولین گره نیز آدرس آخرین گره را ذخیره میکند.
در این مقاله، ما برای معرفی لیست پیوندی حلقوی، از نوع ساده آن استفاده میکنیم.
نمایش لیست پیوندی حلقوی
بیایید ببینیم چگونه میتوانیم یک لیست پیوندی حلقوی را روی یک الگوریتمالگوریتم چیست به زبان ساده و با مثال های فراواندر این مقاله به زبان بسیار ساده و با مثال های متعدد توضیح داده شده که الگوریتم چیست و چه کاربردهایی دارد یا سورس کد (Source Code)سورس کد چیست؟ آیا سورس کد یا سورس برنامه قابلیت اجرا دارند؟این مقاله عالی به سورس کد یا سورس برنامه پرداخته؛ همچنین به بررسی اهداف سورس کد، نحوه ساخت سورس کد و اینکه آیا سورس کد ها قابلیت اجرا دارند پرداخته نشان دهیم. فرض کنید ما یک لیست پیوندی داریم:
در کد این لیست پیوندی، هر گره به صورت زیر نمایش داده میشود:
struct Node {
int data;
struct Node * next;
};
هر گره ساختار دارای یک آیتم داده و یک اشاره گراشاره گر چیست — اشاره گرها در برنامه نویسیاین صفحه عالی توضیح داده اشاره گر چیست و نحوه تعریف اشاره گرها و همین طور اشاره گرها در برنامه نویسی را بررسی کرده سپس انواع اشاره گرها و کاربرد اشاره گرها را گفته به گره ساختار بعدی است. اکنون یک لیست دایرهای ساده با سه عنصر ایجاد میکنیم تا بفهمیم این لیست پیوندی چگونه کار میکند:
/* Initialize nodes */
struct node *last;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
/* Assign data values */
one->data = 1;
two->data = 2;
three->data = 3;
/* Connect nodes */
one->next = two;
two->next = three;
three->next = one;
/* Save address of third node in last */
last = three;
در کد بالا، two, one و three به ترتیب گرههایی با دادههای 1، 2 و 3 هستند.
- برای گره یک: next آدرس گره دو را ذخیره میکند. (قبل از آن هیچ گرهای وجود ندارد.)
- برای گره دو: next آدرس سه را ذخیره میکند.
- برای گره سه: next مقدار NULL را ذخیره میکند (بعد از آن هیچ گرهای وجود ندارد.) و next به گره یک اشاره میکند.
درج در لیست پیوندی
ما میتوانیم عناصر را در 3 موقعیت مختلف از یک لیست پیوندی حلقوی درج کنیم:
- درج در ابتدا
- درج در بین گرهها
- درج در انتها
فرض کنید یک لیست پیوندی حلقوی با عناصر 1، 2 و 3 به شکل زیر داریم:
درج در ابتدا
مراحل درج گره جدید در ابتدای لیست پیوندی حلقوی به شکل زیر است:
- برای گره جدید، حافظهحافظه در کامپیوتر، همه چیز در مورد حافظه در معماری کامپیوتردر این مقاله به بررسی کامل حافظه در کامپیوتر، انواع حافظه در کامپیوتر، کش، روشهای آدرس دهی کش، نگاشت آدرس و موارد دیگر میپردازیم تخصیص دهید.
- دادهها را به گره جدید اختصاص دهید.
- آدرس اولین گره فعلی را در گره جدید ذخیره کنید. (یعنی اشاره کردن گره جدید به اولین گره فعلی)
- آخرین گره را روی گره جدید قرار دهید. (یعنی ساختن گره جدید به عنوان head)
درج در بین دو گره
مراحل درج گره جدید در بین دو گره لیست پیوندی حلقوی به شکل زیر است:
- برای گره جدید، حافظه تخصیص دهید.
- دادهها را به گره جدید اختصاص دهید.
- پیمایش به گره داده شده (فرض کنید این گره، p باشد.)
- اشارهگر next گره جدید را به گره next p اشاره دهید.
- آدرس گره جدید را در next گره p ذخیره کنید.
درج در انتها
مراحل درج گره جدید در انتهای لیست پیوندی حلقوی به شکل زیر است:
- برای گره جدید، حافظه تخصیص دهید.
- دادهها را به گره جدید اختصاص دهید.
- آدرس گره head را در next گره جدید ذخیره کنید.
- اشارهگر آخرین گره فعلی را به گره جدید اشاره دهید.
- گره جدید را به عنوان آخرین گره قرار دهید.
آموزش درس ساختمان داده
قبل از مطالعه ادامه مقاله لازم به ذکر است که برای مشاهده و آموزش سایر مباحث مربوط به درس ساختمان داده و الگوریتم میتوانید از فیلمهای زیر استفاده کنید
فیلم ساختمان داده جلسه 1
فیلم ساختمان داده جلسه 1
فیلم ساختمان داده جلسه 2
فیلم ساختمان داده جلسه 3
فیلم ساختمان داده جلسه 4
فیلم ساختمان داده جلسه 5
فیلم ساختمان داده جلسه 6
فیلم ساختمان داده جلسه 7
فیلم ساختمان داده جلسه 8
حل تست ساختمان و الگوریتم جلسه 1
حل تست ساختمان و الگوریتم جلسه 2
حل تست ساختمان و الگوریتم جلسه 3
حل تست ساختمان و الگوریتم جلسه 4
انواع پیمایشهای درخت
نحوه ساخت درخت BST
آموزش درخت B-Tree
بررسی مرتبه ساخت هیپ
آموزش مرتب سازی سریع
آموزش شبکه شار
حل سوالات ساختمان ارشد کامپیوتر 99
حل ساختمان ارشد 95 بخش 1
حل ساختمان ارشد 95 بخش 2
حذف از لیست پیوندی حلقوی
فرض کنید یک لیست دوگانه با عناصر 1، 2 و 3 داریم. اگر گرهای که باید حذف شود، تنها گره باشد:
- حافظه اشغال شده توسط گره را آزاد کنید.
حذف گره آخر از لیست پیوندی
مراحل حذف گره از انتهای لیست پیوندی حلقوی به شکل زیر است:
- گره را قبل از آخرین گره پیدا کنید. (فرض کنید این گره، temp باشد.)
- آدرس گره را در کنار آخرین گره در temp ذخیره کنید.
- حافظه last را آزاد کنید.
- temp را به عنوان آخرین گره قرار دهید.
حذف گره میانی از لیست پیوندی
مراحل حذف گره میانی از لیست پیوندی حلقوی به شکل زیر است:
- به گرهای که باید حذف شود، پیمایش کنید. (در اینجا، ما میخواهیم گره 2 را حذف کنیم.)
- فرض کنید گره قبل از گره 2، temp باشد.
- آدرس گره بعدی 2 را در temp ذخیره کنید.
- حافظه گره 2 را آزاد کنید.
پیاده سازی لیست پیوندی
Python
# Python code to perform circular linked list operations
class Node:
def __init__(self, data):
self.data = data
self.next = None
class CircularLinkedList:
def __init__(self):
self.last = None
def addToEmpty(self, data):
if self.last != None:
return self.last
# allocate memory to the new node and add data to the node
newNode = Node(data)
# assign last to newNode
self.last = newNode
# create link to iteself
self.last.next = self.last
return self.last
# add node to the front
def addFront(self, data):
# check if the list is empty
if self.last == None:
return self.addToEmpty(data)
# allocate memory to the new node and add data to the node
newNode = Node(data)
# store the address of the current first node in the newNode
newNode.next = self.last.next
# make newNode as last
self.last.next = newNode
return self.last
# add node to the end
def addEnd(self, data):
# check if the node is empty
if self.last == None:
return self.addToEmpty(data)
# allocate memory to the new node and add data to the node
newNode = Node(data)
# store the address of the last node to next of newNode
newNode.next = self.last.next
# point the current last node to the newNode
self.last.next = newNode
# make newNode as the last node
self.last = newNode
return self.last
# insert node after a specific node
def addAfter(self, data, item):
# check if the list is empty
if self.last == None:
return None
newNode = Node(data)
p = self.last.next
while p:
# if the item is found, place newNode after it
if p.data == item:
# make the next of the current node as the next of newNode
newNode.next = p.next
# put newNode to the next of p
p.next = newNode
if p == self.last:
self.last = newNode
return self.last
else:
return self.last
p = p.next
if p == self.last.next:
print(item, “The given node is not present in the list”)
break
# delete a node
def deleteNode(self, last, key):
# If linked list is empty
if last == None:
return
# If the list contains only a single node
if (last).data == key and (last).next == last:
last = None
temp = last
d = None
# if last node is to be deleted
if (last).data == key:
# find the node before the last node
while temp.next != last:
temp = temp.next
# point temp node to the next of last i.e. first node
temp.next = (last).next
last = temp.next
# travel to the node to be deleted
while temp.next != last and temp.next.data != key:
temp = temp.next
# if node to be deleted was found
if temp.next.data == key:
d = temp.next
temp.next = d.next
return last
def traverse(self):
if self.last == None:
print(“The list is empty”)
return
newNode = self.last.next
while newNode:
print(newNode.data, end=” “)
newNode = newNode.next
if newNode == self.last.next:
break
# Driver Code
if __name__ == “__main__”:
cll = CircularLinkedList()
last = cll.addToEmpty(6)
last = cll.addEnd(8)
last = cll.addFront(2)
last = cll.addAfter(10, 2)
cll.traverse()
last = cll.deleteNode(last, 8)
print()
cll.traverse()
++C
// C++ code to perform circular linked list operations
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node* next;
};
struct Node* addToEmpty(struct Node* last, int data) {
if (last != NULL) return last;
// allocate memory to the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
// assign data to the new node
newNode->data = data;
// assign last to newNode
last = newNode;
// create link to iteself
last->next = last;
return last;
}
// add node to the front
struct Node* addFront(struct Node* last, int data) {
// check if the list is empty
if (last == NULL) return addToEmpty(last, data);
// allocate memory to the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
// add data to the node
newNode->data = data;
// store the address of the current first node in the newNode
newNode->next = last->next;
// make newNode as head
last->next = newNode;
return last;
}
// add node to the end
struct Node* addEnd(struct Node* last, int data) {
// check if the node is empty
if (last == NULL) return addToEmpty(last, data);
// allocate memory to the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
// add data to the node
newNode->data = data;
// store the address of the head node to next of newNode
newNode->next = last->next;
// point the current last node to the newNode
last->next = newNode;
// make newNode as the last node
last = newNode;
return last;
}
// insert node after a specific node
struct Node* addAfter(struct Node* last, int data, int item) {
// check if the list is empty
if (last == NULL) return NULL;
struct Node *newNode, *p;
p = last->next;
do {
// if the item is found, place newNode after it
if (p->data == item) {
// allocate memory to the new node
newNode = (struct Node*)malloc(sizeof(struct Node));
// add data to the node
newNode->data = data;
// make the next of the current node as the next of newNode
newNode->next = p->next;
// put newNode to the next of p
p->next = newNode;
// if p is the last node, make newNode as the last node
if (p == last) last = newNode;
return last;
}
p = p->next;
} while (p != last->next);
cout << “\nThe given node is not present in the list” << endl;
return last;
}
// delete a node
void deleteNode(Node** last, int key) {
// if linked list is empty
if (*last == NULL) return;
// if the list contains only a single node
if ((*last)->data == key && (*last)->next == *last) {
free(*last);
*last = NULL;
return;
}
Node *temp = *last, *d;
// if last is to be deleted
if ((*last)->data == key) {
// find the node before the last node
while (temp->next != *last) temp = temp->next;
// point temp node to the next of last i.e. first node
temp->next = (*last)->next;
free(*last);
*last = temp->next;
}
// travel to the node to be deleted
while (temp->next != *last && temp->next->data != key) {
temp = temp->next;
}
// if node to be deleted was found
if (temp->next->data == key) {
d = temp->next;
temp->next = d->next;
free(d);
}
}
void traverse(struct Node* last) {
struct Node* p;
if (last == NULL) {
cout “The list is empty” endl;
return;
}
p = last->next;
do {
cout p->data “ “;
p = p->next;
} while (p != last->next);
}
int main() {
struct Node* last = NULL;
last = addToEmpty(last, 6);
last = addEnd(last, 8);
last = addFront(last, 2);
last = addAfter(last, 10, 2);
traverse(last);
deleteNode(&last, 8);
cout endl;
traverse(last);
return 0;
}
پیچیدگی زمانی و فضایی
پیچیدگی عملیات درج
- عملیاتهای درجی که نیاز به پیمایش ندارند، پیچیدگی زمانیپیچیدگی زمانی الگوریتم چیست؟ معرفی نماد های مجانبیاین صفحه عالی به معرفی پیچیدگی زمانی الگوریتم پرداخته، همچنین انواع نماد های مجانبی و پیچیدگی زمانی های برخی از الگوریتم های مرتب سازی و جستجو را توضیح داده $\mathrm{O}\left(\mathrm{1}\right)$ دارند.
- عملیات درج در بین دو گره که نیاز به پیمایش دارد، دارای پیچیدگی زمانی $\mathrm{O}\left(\mathrm{1}\right)$ است.
- پیچیدگی فضایی عملیات درج $\mathrm{O}\left(\mathrm{1}\right)$ است.
پیچیدگی عملیات حذف
- تمام عملیاتهای حذف با پیچیدگی زمانی $\mathrm{O}\left(\mathrm{1}\right)$ اجرا میشوند.
- پیچیدگی فضایی عملیات حذف از مرتبه $\mathrm{O}\left(\mathrm{1}\right)$ است.
کاربردهای لیست پیوندی حلقوی
لیست پیوندی حلقوی کاربردهای بسیاری دارد که از بین آنها میتوان به موارد زیر اشاره کرد:
- بازیهای چندنفره از این لیست پیوندی استفاده میکنند تا به هر بازیکن، فرصت بازی بدهد.
- یک لیست پیوندی حلقوی، میتواند برای سازماندهی چندین برنامه در حال اجرا در یک سیستم عاملسیستم عامل چیست به زبان ساده، چرا باید از OS استفاده کنیم؟این مقاله عالی به معرفی سیستم عامل (Operating System|OS) به زبان ساده پرداخته، همچنین بررسی کرده که چرا باید از سیستم عامل استفاده کنیم استفاده شود. این برنامهها توسط سیستمعامل تکرار میشوند.
- لیست های پیوندی حلقوی را میتوان در مسائل تخصیص منابع استفاده کرد.
- لیست های پیوندی حلقوی معمولاً برای پیادهسازی بافرهای حلقوی استفاده میشوند.
- لیست های پیوندی حلقوی را میتوان در شبیهسازی و بازی استفاده کرد.
جمع بندی
لیست پیوندی حلقوی (CLL)، نوع خاصی از لیست پیوندی است که در آن، آخرین گره به اولین گره اشاره میکند. در این مقاله با این نوع لیست پیوندی آشنا شدیم و همینطور به بررسی عملیاتهای اساسی آن پرداختیم. همچنین، با کاربردها و پیچیدگیهای زمانی و فضایی و پیادهسازی آن آشنا شدیم.
لیست پیوندی حلقوی چیست؟
لیست پیوندی حلقوی یک نوع از لیست پیوندی است که در آن، همه گرهها برای تشکیل یک دایره یا حلقه به هم متصل میشوند. در یک لیست پیوندی حلقوی، اولین گره و آخرین گره به یکدیگر متصل هستند که یک حلقه را تشکیل میدهند. هیچ NULL در پایان وجود ندارد.
تفاوت بین لیست های پیوندی حلقوی و معمولی چیست؟
در لیست پیوندی معمولی، آخرین گره اشارهگر تهی دارد؛ اما یک لیست پیوندی حلقوی همیشه به head لیست پیوندی اشاره میکند؛ به این معنی که لیست پیوندی با head شروع میشود و در پایان دوباره به head اشاره میکند. همانطور که نامش نشان میدهد، لیستهای پیوندی حلقوی به شکل دایره هستند و یک دایره انتهایی ندارند.
کاربرد لیست پیوندی حلقوی چیست؟
از کاربردهای لیست پیوندی حلقوی میتوان به این موارد اشاره کرد: بازیهای چند نفره از این لیست پیوندی استفاده میکنند تا به هر بازیکن فرصت بازی بدهد؛ یک لیست پیوندی حلقوی میتواند برای سازماندهی چندین برنامه در حال اجرا در یک سیستمعامل استفاده شود. این برنامهها توسط سیستمعامل تکرار میشوند؛ لیستهای پیوندی حلقوی را میتوان در مسائل تخصیص منابع استفاده کرد؛ لیستهای پیوندی حلقوی معمولاً برای پیادهسازی بافرهای حلقوی استفاده میشوند و لیستهای پیوندی حلقوی را میتوان در شبیهسازی و بازی استفاده کرد.
مزایای لیست پیوندی حلقوی چیست؟
عملیاتها در لیست پیوندی حلقوی کارآمدتر هستند. از آنجایی که آخرین گره لیست به گره اول برمی گردد، لیستهای پیوندی دایرهای را میتوان سریع و کارآمد پیمایش کرد. این باعث میشود آنها برای برنامههایی مفید باشند که به پیمایش مکرر نیاز دارند، مانند اجرای صف و جدول هش و...
معایب لیست پیوندی حلقوی چیست؟
از معایب لیست پیوندی حلقوی میتوان به این موارد اشاره کرد: لیستهای دایرهای در مقایسه با لیستهای پیوندی ساده پیچیدهتر هستند؛ معکوس لیست دایرهای در مقایسه با لیستهای ساده یا دوطرفه پیچیدهتر است؛ اگر به دقت مورد استفاده قرار نگیرد، ممکن است کد در یک حلقه بینهایت حرکت کند و یافتن انتهای لیست و کنترل حلقه سختتر است.