C++의 순환 이중 연결 목록

Jinku Hu 2023년10월12일 C++ C++ Data Structure
C++의 순환 이중 연결 목록

이 기사에서는 C++에서 순환 이중 연결 목록을 구현하는 방법을 보여줍니다.

C++에서 처음부터 순환 이중 연결 목록 데이터 구조

이중 연결 목록은 각 노드가 다음 노드와 이전 노드 모두에 대한 포인터를 저장하는 데이터 구조입니다. 따라서 std::deque와 같은 컨테이너를 구현하는 것이 최적의 선택입니다. 마지막 노드의 next 멤버가 목록의 시작을 가리키고 첫 번째 노드도 이전 노드로 마지막 노드를 가리키도록 이중 연결 목록을 원형으로 만드는 것이 좋습니다.

먼저 목록을 구성하는 데 사용되는 ListNode라는 struct를 선언해야 합니다. 다음으로 ListNode* 유형의 데이터 멤버 2개와 멤버 함수 3개로 구성된 CircularList 클래스를 정의합니다.

string 값을 받아들이고 첫 번째 노드를 초기화하는 생성자를 하나만 포함하기로 결정했지만 이 부분은 프로그래머가 적절하다고 생각하는 대로 수정할 수 있습니다. headend의 두 데이터 멤버는 첫 번째 노드와 마지막 노드를 저장합니다. 또한 목록의 각 측면에 요소를 추가하는 별도의 기능이 있습니다.

#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

struct ListNode {
  struct ListNode *next = nullptr;
  struct ListNode *prev = nullptr;
  string data;
} typedef ListNode;

class CircularList {
 public:
  explicit CircularList(string data) {
    head = new ListNode;
    head->next = head;
    head->prev = head;
    head->data = std::move(data);
    end = head;
  };

  ListNode *insertNodeEnd(string data);
  ListNode *insertNodeHead(string data);
  void printNodes();

  ~CircularList();

 private:
  ListNode *head = nullptr;
  ListNode *end = nullptr;
};

ListNode *CircularList::insertNodeEnd(string data) {
  auto new_node = new ListNode;
  new_node->next = head;
  new_node->prev = end;
  new_node->data = std::move(data);

  head->prev = new_node;
  end->next = new_node;
  end = end->next;
  return end;
}

ListNode *CircularList::insertNodeHead(string data) {
  auto new_node = new ListNode;
  new_node->next = head;
  new_node->prev = end;
  new_node->data = std::move(data);

  head->prev = new_node;
  end->next = new_node;
  head = new_node;
  return head;
}

CircularList::~CircularList() {
  while (head != end) {
    auto tmp = head;
    head = head->next;
    delete tmp;
  }
  delete head;
}

void CircularList::printNodes() {
  auto count = 0;
  auto tmp = head;
  while (tmp != end) {
    cout << "node " << count << " - data: " << tmp->data << endl;
    tmp = tmp->next;
    count++;
  }
  cout << "node " << count << " - data: " << tmp->data << endl;
}

int main() {
  CircularList clist("Xenial");

  clist.insertNodeHead("Saucy");
  clist.insertNodeEnd("Quantal");

  clist.printNodes();
  cout << " ----------------------------------- " << endl;

  clist.insertNodeHead("Bionic");
  clist.printNodes();

  return EXIT_SUCCESS;
}

출력:

node 0 - data: Saucy
node 1 - data: Xenial
node 2 - data: Quantal
 -----------------------------------
node 0 - data: Bionic
node 1 - data: Saucy
node 2 - data: Xenial
node 3 - data: Quantal

요소 삽입을 위한 일반적인 알고리즘은 새 ListNode 개체를 할당하고 해당 노드 포인터를 해당 구성원에 할당한 다음 필요에 따라 head/end 구성원을 수정하는 작업을 수반합니다. 코드의 정확성을 검사해야 할 수도 있으므로 목록 내용을 표시하는 printNodes 기능도 포함합니다. 목록 개체가 범위를 벗어난 후에는 모든 메모리를 할당 해제하는 것을 잊지 말아야 합니다. 후자의 함수는 소멸자로 구현됩니다.

튜토리얼이 마음에 드시나요? DelftStack을 구독하세요 YouTube에서 저희가 더 많은 고품질 비디오 가이드를 제작할 수 있도록 지원해주세요. 구독하다
작가: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

관련 문장 - C++ Data Structure