Կապակցված ցուցակ (Linked List)

Հաջորդական տվյալների հետ աշխատելիս սովորաբար օգտագործում ենք զանգվածներ կամ ցանկեր, որպեսզի պահենք տվյալներն ու հասանելիություն ունենանք դրանց։ Այնուամենայնիվ, որոշ պարագաներում ավելի արդյունավետ է օգտվել կապակցված ցուցակից։ Մասնավորապես, եթե ծրագիրը բազմիցս պետք է ցուցակի սկզբում նոր տարր ավելացնի կամ ջնջի, կապակցված ցուցակը կարող է լինել ավելի արագ։
Կապակցված ցուցակն ամենահիմնական տվյալների կառուցվածքներից մեկն է։ Այն ունի տարրերի ցանկ, կարող է այդ ցանկը թարմացնել նոր տարրեր ավելացնելով և հասանելիություն ունենալ փուլայինի պես։ Կապակցված ցուցակ օգտագործելիս, ամեն տարրը սովորաբար անվանում ենք Node (հանգույց), որն իր մեջ պարունակում է տվյալ և հղում դեպի հաջորդ Node-ը։ Միակողմանի կապակցված ցուցակում (singly linked list) յուրաքանչյուր տարր (Node) պարունակում է հղում դեպի հաջորդ հանգույցը, իսկ վերջին հանգույցի հղումը ուղղված է ոչնչի (null)։ Գրականության մեջ, կապակցված ցուցակի առաջին տարրը կոչվում է head, իսկ վերջինը՝ tail։ Մեկիկողմանի կապակցված ցուցակի մի օրինակ իրագործվում է ներքևում:
class Node:
    def __init__(self, data):
        self.data = data               # Պահպանում է հանգույցի արժեքը
        self.after = None              # Պահպանում է հղում դեպի հաջորդ հանգույցը


class LinkedList:
    def __init__(self):
        self.head = None               # Սկզբում ցուցակում տարրեր չկան

    def append(self, data):            # Ցուցակին նոր հանգույց է ավելացնում վերջում
        new_node = Node(data)          # Ստեղծում է հանգույց, որը պահում է data
        if self.head is None:          # Եթե ցուցակը դեռ դատարկ է
            self.head = new_node       # head-ը ուղղում ենք նոր հանգույցին
            return
        current = self.head            # Սկսում ենք անցնել ցուցակով head-ից
        while current.after:           # Քանի դեռ չենք հասել վերջին հանգույցին
            current = current.after    # Շարունակում ենք դեպի հաջորդ հանգույց
        current.after = new_node       # Վերջին հանգույցի հղումը կապում ենք նոր հանգույցի հետ

    def print(self):                   # Տպում է ցուցակի բոլոր տարրերը
        current = self.head            # Սկսում ենք head-ից
        while current:                 # Քանի դեռ չենք հասել ցուցակի վերջ
            print(current.data, end='\n' if current.after is None else ' --> ')
            current = current.after    # Շարունակում ենք դեպի հաջորդ հանգույց


names = LinkedList()                   # Ստեղծում է դատարկ LinkedList
names.append('Anna')                   # Ավելացնում է Anna-ն ցուցակում
names.append('Bob')                    # Ավելացնում է Bob-ը ցուցակում
names.append('Sona')                   # Ավելացնում է Sona-ն ցուցակում
names.print()                          # Anna --> Bob --> Sona
notion image
Վերոնշյալ իրագործման մեջ մենք ունենք երկու դասեր՝ Node և LinkedList։ Node-ն ունի երկու հատկություն՝ data և after։ data-ն պահում է հանգույցի արժեքը, իսկ after-ը պահում է հղումը դեպի հաջորդ հանգույցը։ LinkedList-ը ունի մեկ հատկություն՝ head, որը պահում է կապակցված ցուցակի առաջին հանգույցի հղումը։ Նոր հանգույց ավելացնելու համար օգտագործվում է append() մեթոդը, իսկ print() մեթոդը տպում է բոլոր տարրերը։

Երկկողմանի կապակցված ցուցակ (Doubly Linked List)

Բացի այդ, կարելի է օգտագործել նաև երկկողմանի կապակցված ցուցակ, որտեղ յուրաքանչյուր տարր ունի հղում և՛ դեպի հաջորդ, և՛ դեպի նախորդ հանգույցը। Սա հնարավորություն է տալիս հեշտությամբ անցնել ցուցակով երկու ուղղություններով։

Կապակցված ցուցակի վերլուծություն

Կապակցված ցուցակների հետ աշխատելիս կարևոր է հիշել.
  • Ցուցակային որևէ տարր գտնելը տևում է ժամանակ, քանի որ հարկավոր է սկսել head-ից ու հերթով անցնել մինչև գտնել անհրաժեշտ տարրը։
  • Եթե մենք գիտենք այն Node-ը, որի հետևում պետք է տեղադրել նոր հանգույց, ապա տեղադրումը տևում է ժամանակ, քանի որ բավարար է ուղղակի թարմացնել հարակից հանգույցների հղումները։
  • Նույն ձևով, եթե մենք գիտենք, թե որ Node-ը պետք է ջնջենք, ապա ջնջումը նույնպես տևում է , քանի որ բավարար է թարմացնել հարակից հանգույցների հղումները։
  • Կապակցված ցուցակներում ամեն հանգույց պահում է նաև լրացուցիչ հղում, ինչը ընդհանուր առմամբ ավելի շատ հիշողություն է պահանջում, քան զանգվածները։

Առաջադրանք

Տրված է n հարցում։ Անրաժեշտ է դրանցից յուրաքանչյուրն իրականացնել։ Հարցումների 2 տեսակ կա.
  1. Տեղադրել թիվը ցուցակի սկզբում։
  1. Տպել ամբողջ ցուցակը։

Մուտք

Մուտքի առաջին տողում տրված է մեկ ամբողջ թիվ n (1 ≤ n ≤ 1000)՝ հարցումների քանակը։
Հաջորդ n տողերը պարունակում են հարցումները՝ print, եթե պետք է տպել ամբողջ ցուցակը, և insert x, եթե անհրաժեշտ է թիվ x ավելացնել ցուցակի սկզբում ( ≤ x ≤

Ելք

Ծրագիրը պետք է պատշաճ ձևով իրականացնի բոլոր հարցումները և տպի ցուցակը՝ տարրերը բաժանելով բացատներով։

Օրինակներ

Մուտք
Ելք
6 insert 8 print insert 10 insert -2 insert -6 print
8 -6 -2 10 8
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue