如何解决队列中的 Delete_at 无法正常工作
所以我想在c++中实现一个队列数据结构,并使用一些特殊的方法,比如delete_at(),考虑到队列数据结构的约束,所以我使用dequeue方法来实现它并获取所有的数据不等于用户想要删除并存储在数组中的索引,以便将其全部重新排入队列,但没有用户想要删除的索引,但是没有删除任何内容,所以这里是代码:
#include <list>
using namespace std;
class Queue{
private:
struct node {
int data;
struct node *next;
};
struct node* front = NULL;
struct node* rear = NULL;
public:
void Enqueue(int d) {
struct node* tmp=new node;
if (rear == NULL) {
tmp->next = NULL;
tmp->data = d;
rear=tmp;
front = rear;
}
else {
rear->next = tmp;
tmp->data = d;
tmp->next = NULL;
rear = tmp;
}
}
int Dequeue() {
struct node* tmp = front;
int data=front->data;
if (front == NULL) {
return 0;
}
else{
if (tmp->next != NULL) {
tmp=front;
front = front->next;
delete tmp;
}
else {
tmp=front;
delete tmp;
front = NULL;
rear = NULL;
}
}
return data;
}
void display() {
struct node* temp = front;
if (front == NULL) {
cout<<"Queue is empty"<<endl;
return;
}
while (temp != NULL) {
cout<<temp->data<<"\n";
temp = temp->next;
}
}
int Size() {
struct node* temp = front;
int cnt=0;
while (temp != NULL) {
cnt++;
temp = temp->next;
}
return cnt;
}
void Delete_at(int index){
int i=0;
int ar_size=Size();
int data_arr[ar_size-1];
if(index > Size()){
cout<<"\n"<<"Error: out of bounds !";
return;
}
while(i<ar_size){
if (i==(index-1)){
Dequeue();
}
else{
data_arr[i]=Dequeue();
}
i++;
}
i=0;
while(i<ar_size){
Enqueue(data_arr[i]);
i++;
}
}
};
int main() {
int i=0;
Queue q;
q.Enqueue(2);
q.Enqueue(6);
q.Enqueue(7);
q.Enqueue(1);
q.Enqueue(2);
q.Enqueue(4);
q.Delete_at(2);
q.display();
return 0;
}
解决方法
您的代码通常有两个主要问题,Delete_at()
不能简单地调用 Dequeue()
。作为一般说明,您的代码包含可以简单合并的重复表达式。例如,Enqueue()
可以简洁地写成:
void Enqueue(int d) {
struct node *tmp = new node;
tmp->next = nullptr;
tmp->data = d;
if (rear == nullptr) {
front = rear = tmp;
size = 1;
}
else {
rear->next = tmp;
rear = tmp;
size += 1;
}
}
您的 Dequeue()
函数将在检查 front->data
之前检查 front == nullptr
段错误。您必须在取消引用之前进行检查,例如
int Dequeue() {
struct node *tmp = front;
int data;
if (front == nullptr) { /* (must check before dereference (front->data) */
return 0;
}
data = front->data;
size -= 1;
if (tmp->next != nullptr) {
front = front->next;
}
else {
front = nullptr;
rear = nullptr;
}
delete tmp;
return data;
}
您的 Delete_at()
函数必须删除特定索引处的节点。这要求您在整个列表中维护 ->next
链接,更新已删除节点之前的 prev->next
以指向要删除的节点之后的节点。您可以通过迭代节点的地址和指向节点的指针来做到这一点。当您到达要删除的索引时,您只需将当前位于该节点地址的内容替换为下一个节点并删除当前节点,请参阅:Linus on Understanding Pointers
void Delete_at (size_t index) {
struct node *pnode = front,/* pointer to node */
**ppnode = &front; /* address of node */
if (index >= Size()) { /* validate with >= Size() */
std::cerr << '\n' << "Error: out of bounds !";
return;
}
while (index--) { /* loop index times */
ppnode = &pnode->next; /* address of next node */
pnode = pnode->next; /* pointer to next node */
}
*ppnode = pnode->next; /* replace struct at address with next */
delete pnode; /* delete removed node */
size -= 1;
}
您的 Size()
函数只是简化为“getter”函数:
size_t Size() {
return size;
}
稍微更新您的示例并注意 Why is “using namespace std;” considered bad practice? 您的完整代码现在可以是:
#include <list>
#include <iostream>
class Queue{
private:
struct node {
int data;
struct node *next;
};
struct node *front = nullptr;
struct node *rear = nullptr;
size_t size;
public:
void Enqueue(int d) {
struct node *tmp = new node;
tmp->next = nullptr;
tmp->data = d;
if (rear == nullptr) {
front = rear = tmp;
size = 1;
}
else {
rear->next = tmp;
rear = tmp;
size += 1;
}
}
int Dequeue() {
struct node *tmp = front;
int data;
if (front == nullptr) { /* (must check before dereference (front->data) */
return 0;
}
data = front->data;
size -= 1;
if (tmp->next != nullptr) {
front = front->next;
}
else {
front = nullptr;
rear = nullptr;
}
delete tmp;
return data;
}
void Display() {
struct node *temp = front;
if (front == nullptr) {
std::cout << "Queue is empty" << '\n';
return;
}
while (temp != nullptr) {
std::cout << temp->data << '\n';
temp = temp->next;
}
}
size_t Size() {
return size;
}
void Delete_at (size_t index) {
struct node *pnode = front,/* pointer to node */
**ppnode = &front; /* address of node */
if (index >= Size()) { /* validate with >= Size() */
std::cerr << '\n' << "Error: out of bounds !";
return;
}
while (index--) { /* loop index times */
ppnode = &pnode->next; /* address of next node */
pnode = pnode->next; /* pointer to next node */
}
*ppnode = pnode->next; /* replace struct at address with next */
delete pnode; /* delete removed node */
size -= 1;
}
};
int main() {
Queue q;
q.Enqueue(2);
q.Enqueue(6);
q.Enqueue(7);
q.Enqueue(1);
q.Enqueue(2);
q.Enqueue(4);
q.Display();
std::cout << "\nq.Delete_at(2)\n\n";
q.Delete_at(2);
q.Display();
}
示例使用/输出
$ ./bin/queue_delete_at
2
6
7
1
2
4
q.Delete_at(2)
2
6
1
2
4
检查一下,如果您还有其他问题,请告诉我。
使用评论的附加约束进行编辑
根据您的评论,您的限制是只能在 Dequeue()
中使用 Enqueue()
和 Delete_at()
而不能使用指针等......您可以这样做,但理解它会与简单地删除索引处的节点相比,效率低得可怕。您基本上必须在分配的内存块中保存 (Dequeue()
) 整个队列数据,省略要删除的索引。然后,您需要遍历所有保存的值,调用 Enqueue()
以重新填充您的列表。
你可以这样做:
void Delete_at (size_t index) {
if (index >= Size()) { /* validate with >= Size() */
std::cerr << '\n' << "Error: out of bounds !";
return;
}
size_t nelem = Size();
int *arr = new int [nelem],n = 0;
for (size_t i = 0; i < nelem; i++) {
int tmp = Dequeue();
if (i != index && tmp)
arr[n++] = tmp;
}
for (size_t i = 0; i < (size_t)n; i++)
Enqueue (arr[i]);
delete[] arr;
}
(相同的输出)
对于可读性较差的 C++ 化演示文稿,您可以将第一个循环替换为:
for (int i = 0,j = Dequeue(); j; i++,j = Dequeue())
if (static_cast<size_t>(i) != index)
arr[n++] = j;
使用至少一个单独的列表指针会很好,这样您就可以在删除旧列表的同时构建新列表,但您的类/结构未设置为使用其他指针。因此,您基本上只能缓冲除要删除的索引之外的所有值,然后重新创建您的队列。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。