我正在尝试为循环双向链表创建字符串值的插入函数。我看到创建一个虚拟节点有利于这样做,所以我可以消除特殊情况,例如当列表为空时。问题是我在虚拟头节点上找不到很多好的信息。我理解他们的目的,但我不明白我是如何创建/实现它的。
欣赏所有代码示例的人,尽管有人可以看一下,但我试图自己解决这个问题。
#include <iostream>
#include <string>
using namespace std;
typedef string ListItemType;
struct node {
node * next;
node * prev;
ListItemType value;
};
node * head;
node * dummyHead = new node;
void insert(const ListItemType input, node * & within);
void main(){
insert("bob",dummyHead);
}
void insert( const ListItemType input, node * &ListHead){
node *newPtr = new node;
node *curr;
newPtr->value = input;
curr = ListHead->next; //point to first node;
while (curr != ListHead && input < curr->value){
curr = curr->next;
}
//insert the new node pointed to by the newPTr before
// the node pointed to by curr
newPtr->next = curr;
newPtr->prev = curr->prev;
curr->prev = newPtr;
newPtr->prev->next = newPtr;
}
答案 0 :(得分:4)
对于循环双向链表,您可以设置1个前哨节点,其中“next”和“prev”在列表为空时指向自身。当列表不为空时,sentinel-&gt; next指向第一个元素,sentinel-&gt; prev指向最后一个元素。有了这些知识,你的插入和删除功能看起来就像这样。
这是非常基本的,您的LinkedList和Node类可能以不同的方式实现。那没问题。主要的是insert()和remove()函数实现,它显示了sentinel节点如何消除检查NULL值的需要。
希望这有帮助。
class DoublyLinkedList
{
Node *sentinel;
int size = 0;
public DoublyLinkedList() {
sentinel = new Node(null);
}
// Insert to the end of the list
public void insert(Node *node) {
// being the last node, point next to sentinel
node->next = sentinel;
// previous would be whatever sentinel->prev is pointing previously
node->prev = sentinel->prev;
// setup previous node->next to point to newly inserted node
node->prev->next = node;
// sentinel previous points to new current last node
sentinel->prev = node;
size++;
}
public Node* remove(int index) {
if(index<0 || index>=size) throw new NoSuchElementException();
Node *retval = sentinel->next;
while(index!=0) {
retval=retval->next;
index--;
}
retval->prev->next = retval->next;
retval->next->prev = retval->prev;
size--;
return retval;
}
}
class Node
{
friend class DoublyLinkedList;
string *value;
Node *next;
Node *prev;
public Node(string *value) {
this->value = value;
next = this;
prev = this;
}
public string* value() { return value; }
}
答案 1 :(得分:2)
为什么要尝试使用虚拟节点? 我希望你能在没有虚拟节点的情况下处理它。 例如:
void AddNode(Node node)
{
if(ptrHead == NULL)
{
ptrHead = node;
}else
{
Node* itr = ptrHead;
for(int i=1; i<listSize; i++)
{
itr = itr->next;
}
itr->next = node;
}
listSize++;
}
以上是处理没有虚节点的链表的示例。
答案 2 :(得分:1)
对于没有虚节点的循环双链表,第一个节点的前一个指针指向最后一个节点,最后一个节点的下一个指针指向第一个节点。列表本身有一个指向第一个节点的头指针,以及一个指向最后一个节点的尾指针和/或一个计数。
对于虚节点,第一节点先前指针指向虚节点,最后节点下一指针指向虚节点。虚节点指针可以指向虚节点本身或为空。
HP / Microsoft STL列表函数使用虚拟节点作为列表头节点,下一个指针用作指向第一个真实节点的头指针,前一个指针用作指向最后一个真实节点的尾指针。 / p>
答案 3 :(得分:1)
#include <iostream>
#include <string>
using namespace std;
typedef string ElementType;
struct Node
{
Node(){}
Node(ElementType element, Node* prev = NULL, Node* next = NULL):element(element){}
ElementType element;
Node* prev;
Node* next;
};
class LinkList
{
public:
LinkList()
{
head = tail = dummyHead = new Node("Dummy Head", NULL, NULL);
dummyHead->next = dummyHead;
dummyHead->prev = dummyHead;
numberOfElement = 0;
}
void insert(ElementType element)
{
Node* temp = new Node(element, NULL, NULL);
if (0 == numberOfElement)
{
head = tail = temp;
head->prev = dummyHead;
dummyHead->next = head;
tail->next = dummyHead;
dummyHead->prev = tail;
}
else
{
tail->next = temp;
temp->prev = dummyHead->next;
temp->next = dummyHead;
dummyHead->next = temp;
tail = temp;
}
numberOfElement += 1;
}
int length() const { return numberOfElement; }
bool empty() const { return head == dummyHead; }
friend ostream& operator<< (ostream& out, const LinkList& List);
private:
Node* head;
Node* tail;
Node* dummyHead;
int numberOfElement;
};
ostream& operator<< (ostream& out, const LinkList& List)
{
Node* current = List.head;
while (current != List.dummyHead)
{
out<<current->element<<" ";
current = current->next;
}
out<<endl;
return out;
}
int main()
{
string arr[] = {"one", "two", "three", "four", "five"};
LinkList list;
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; ++i)
{
list.insert(arr[i]);
}
cout<<list<<endl;
}
我认为此代码可以帮助您。当您想要实现某些数据结构时,您必须有一个清晰的蓝图。
答案 4 :(得分:0)
在构造函数
中执行以下操作ptrHead = new Node();
listSize = 1;
如果你也有尾巴,
ptrHead->next = ptrTail;
上面的代码将创建虚拟节点。 确保实现不受此虚拟节点的影响。
例如:
int getSize()
{
return listSize-1;
}