01/10/2018, 00:57

Làm sao để xóa một node có dữ liệu data là kiểu struct trong danh sách liên kết đơn?

Mình phải làm bài tập liên quan đến xóa một node có cấu trúc struct là vé tàu. Nhưng khi duyệt các node xem có dữ liệu nào trùng vs dữ liệu cho trước không thì mình nó lại báo lỗi ở câu k->data=q->data trong đó k và q là hai node. q là node chứa dữ liệu nhập vào để duyệt.

Trang Nấm viết 03:02 ngày 01/10/2018

đây là code của mình

void xoadau(Queuevetau*Q)
{
	Nodevetau*p = Q->head;
	Q->head=Q->head->next;
	delete p;
}

// xoa mot ve nam o cuoi hang doi B
void xoacuoi(Queuevetau*Q)
{
	Nodevetau*p;
	for(Nodevetau*k=Q->head; k!=NULL; k= k->next)
	{
		if( k == Q->tail)
		{
			Q->tail=p;
			p->next=NULL;
			delete k;
			return;
		}
		p=k;
	}
}
// xoa mot ve nam sau mot node bat ki
void xoasaumotnode(Queuevetau*Q, Nodevetau*q)
{
	Datavetau data;
	Nodevetau*p;
	for(Nodevetau*k=Q->head; k!=NULL; k=k->next)
	{
		if(k->data == q->data)
		{
			p=k->next;
			k->next = p ->next;
			delete p;
			return;
		}
	}
}
// xoa mot ve có du lieu data
void xoanodekhoabatky(Queuevetau*Q, Datavetau data)
{
	Datavetau data;
	Datavetau a = data;
	    printf("\nNhap va thong tin ve can xoa: ");
		printf("\n\nMa ve tau: ");
	    scanf("%d", &a.ma_ve);
	    printf("\nLo trinh: ");
	    scanf("%s", a.lo_trinh);
        printf("\nSo ghe: ");
        scanf("%d", &a.so_ghe);
        printf("\nThoi gian khoi hanh: ");
        scanf("%s", a.thoi_gian);
        printf("\nGia ve: ");
        scanf("%d", &a.gia_ve);
	if(Q->head->data == data)
	{
		xoadau(Q);
		return;
	}
	if(Q->tail->data == data)
	{
		xoacuoi(Q);
		return;
	}
	Nodevetau *p;
	for(Nodevetau*k=Q->head; k!= NULL; k=k->next)
	{
		if(k->data == data)
		{
			xoasaumotnode(Q, p);
		}
		p=k;
	}
}

viết 03:00 ngày 01/10/2018

trong hàm xoacuoi() thì p chưa được gán giá trị (p chưa trỏ vào đâu) mà gọi p->next=NULL; sao được @_@ Hơn nữa dslk đơn thì ko nên có hàm xóa cuối. Thêm đầu, thêm cuối, xóa đầu là đủ rồi.

còn cái hàm xóa sau 1 node thì cung cấp Nodevetau* để so sánh làm gì? Sao ko cung cấp hẳn luôn 1 cái vé tàu v chẳng hạn? Vì so sánh k->data == q->data thì có khác gì k->data == v. Hàm xóa sau 1 node chỉ đơn giản là xóa sau node đó là đủ. Đâu có cần cung cấp thêm Q làm gì…

void xoasaumotnode(Nodevetau* q)
{
    if (!q->next) return;  //ko có node next
    Node* todelete = q->next;
    q->next = q->next->next;
    delete todelete;
}
Trang Nấm viết 03:05 ngày 01/10/2018

p đã được gán giá trị bằng Q->tail rồi mà. làm như thế để chặt đứt mối liên hệ với node cần xóa, biến p (node trước node cần xóa) trở thành node cuối cùng

Trang Nấm viết 03:00 ngày 01/10/2018

tại vì mình làm hai hàng đợi cho nên phải cung cấp thêm Q thì nó mới hiểu >.<

viết 02:59 ngày 01/10/2018

bạn ghi Q->tail=p; mà?? p có được gán cho cái gì đâu. Xóa đuôi ko phải là tìm node tail, mà tìm node đứng trước tail mới đúng. Phải kiểm tra if (k->next == Q->tail) rồi sau đó xóa tail, gán tail bằng k, k->next = NULL.

mỗi lần xóa tail lại phải lướt tất cả các phần tử trong dslk, vậy thì quá tốn công so với xóa đầu/thêm đầu/thêm đuôi.

đáng lẽ ko có thêm đuôi luôn. Có thêm đuôi thì phải có thêm node tail, hàm xóa sau 1 node phải kiểm tra xem node sau đó có phải tail ko nữa, nếu là tail thì phải trỏ tail lại cho đúng, tốn thời gian nữa.

Trang Nấm viết 03:00 ngày 01/10/2018

cái dòng cuối cùng của mình trong hàm là gán p=k; đó thôi. nếu k=Q-> tail tức là k là node cuối cùng, thì p sẽ là node trước node đó do chạy vòng lặp for.

viết 03:13 ngày 01/10/2018

như vậy vẫn bị lỗi khi dslk chỉ có 1 phần tử, gọi xóa cuối sẽ lỗi ngay vì câu lệnh if sẽ trả về true ngay lập tức

Trang Nấm viết 03:02 ngày 01/10/2018

thì nó đã có hàm xóa đầu rồi mà >.<. quan trọng làm cái hàm xóa một khóa bất kỳ thôi, 3 hàm kia sẽ nằm trong cái hàm đó để xử lý mọi trường hợp

viết 03:06 ngày 01/10/2018
  • gọi del là node cần xóa (node q->next)
...->[ ]->[X]->[Y]->[ ]->...
      ^q   ^del
  • do có thêm cái đuôi thì phải kiểm tra del có bằng Q->tail ko, nếu bằng thì phải update tail
(trường hợp xóa tail)
...->[ ]->[X]->NULL
      ^q   ^del
           ^tail
chuyển thành
...->[ ]->[X]->NULL
      ^q   ^del
      ^tail
  • gán q->next = del->next
...->[ ]------>[Y]->[ ]->...
      ^q  [X]<--del

(trường hợp xóa tail)
...->[ ]------>NULL
      ^q  [X]<--del
      ^tail
  • xóa del
...->[ ]->[Y]->[ ]->...
      ^q

(trường hợp xóa tail)
...->[ ]->NULL
      ^q
      ^tail

void xoasaumotnode(Queuevetau*Q, Nodevetau*q)
{
    Node* del = q->next;
    if (del == Q->tail) Q->tail = q;
    q->next = del->next;
    delete del;
}
Trang Nấm viết 03:13 ngày 01/10/2018

ý tưởng của mình là chưa biết cái node trước node cần xóa là node nào cơ. Chỉ biết node cần xóa có dữ liệu là data cũng chưa biết nó nằm ở đâu. phải tìm ra node cần xóa đó và node nằm trước nó để thực hiện xóa.

viết 03:02 ngày 01/10/2018

phải tìm ra node cần xóa đó và node nằm trước nó để thực hiện xóa.

ý tưởng đúng rồi, nhưng:

  • lỡ ko tìm thấy node cần xóa thì thế nào? (Q rỗng, hoặc ko có node nào có data giống như data cho trước)
  • tìm thấy node cần xóa nhưng ko tìm thấy node nằm trước thì thế nào? (node head có data giống data cho trước, và ko có node nào nằm trước node head)

xét 1 hồi dễ khùng lắm.

Bài liên quan
0