30/09/2018, 18:11

Có 2 con trỏ *p, và *q thì p->q và p=q có khác nhau không?

mọi người cho mình hỏi tí: Có 2 con trỏ *p, và *q thì p->q và p=q có khác nhau không vậy ?

Mai Anh Dũng viết 20:20 ngày 30/09/2018

Có 2 con trỏ *p, và *q

Con trỏ này kiểu gì?

p->q

Phải có kiểu con trỏ mới nói được

chienbinhthep viết 20:17 ngày 30/09/2018

giả sử cả 2 con trỏ cùng kiểu anh ạ

Mai Anh Dũng viết 20:15 ngày 30/09/2018

Em không hiểu con trỏ rồi, nếu con trỏ là kiểu int, thì p->q không tồn tại.

Nếu con trỏ kiểu link list (danh sách liên kết) thì p->q tồn tại, em đang học link list thì đưa cấu trúc linklist lên anh giải thích thêm.

chienbinhthep viết 20:23 ngày 30/09/2018

dạ, phần này e đang còn kém, mong anh giải thích rõ hơn ạ

struct node {
    int data;
    struct *pnext;
};
....
// tạo 1 node
node *getnode() {
    node *p= new node;
    p->data;
    p->pnext=NULL;
    return p;
}

e thấy giá trị của p ở trong node kia luôn không đổi, câu lệnh p->pnext có nghĩa là gì ạ ?

Mai Anh Dũng viết 20:16 ngày 30/09/2018

p->pnext là một phép truy vấn dữ liệu, trong đó p là con trỏ, trỏ tới struct node

Struct này code sai rồi

struct node {
    int data;
    struct *pnext;
};

Phải sửa lại thế này

struct node {
    int data;
    struct node *pnext;
};

Trong đó *pnext là một con trỏ, trỏ tới kiểu dữ liệu struct node.


Quay trở lại vấn đề

p->pnext là một phép truy vấn dữ liệu.

p->pnext tức là câu truy vấn giá trị của pnext là gì?


p=q là một phép gán đơn giản

Bụng Bự viết 20:21 ngày 30/09/2018

Cám ơn a Đạt, em đang như trên mây về cái phần này

pham van trinh viết 20:22 ngày 30/09/2018
struct *pnext;

Lại sai hả anh đạt @ltd

Minh Hoàng viết 20:13 ngày 30/09/2018

Đúng vậy, struct <kiểu dữ liệu> <tên biến>;
ví dụ: struct node *pnext;

Mai Anh Dũng viết 20:26 ngày 30/09/2018

Như @Rok_Hoang đã trả lời, đó là vì nó không đúng cú pháp, em code thử chạy thử sẽ biết.

Interns viết 20:19 ngày 30/09/2018

em cũng đang mệt mỏi với phần danh sách liên kết anh @ltd ơi không biết nguyên lý hoạt động của mỗi hàm(tạo Node mới, chèn 1 phân tử vào đầu hoặc cuối danh sách…) nó như thế nào (nhất là con trỏ nó cứ trỏ lung tung, cho dù em cũng nắm được kiến thức con trỏ cơ bản), chỉ biết học thuộc code và bê vô thôi. Hỏi thầy cô thì thầy cô cũng không giải thích kĩ, chỉ nói mặc định nó là như thế và không giải thích được tại sao nó lại như thế. Giờ đang bế tắc không biết phải làm sao?

Mai Anh Dũng viết 20:21 ngày 30/09/2018

Xem video hướng dẫn của anh, anh nói rất kỹ mà.

Interns viết 20:14 ngày 30/09/2018

ok để em vào xem. Em quên mất là anh có làm bài hướng dẫn về phần này!

Võ Hoàng Việt viết 20:19 ngày 30/09/2018

Bạn nên xem series con trỏ của anh Nguyễn Việt Nam Sơn trước khi bước qua phần cấu trúc dữ liệu, vì phần này ứng dụng con trỏ khá nhiều, nếu không nắm được con trỏ thì rất dễ bị tẩu hỏa @@. Dưới đây là code demo về cấu trúc dữ liệu đơn giản, hi vọng giúp được bạn :

#include <iostream>

using namespace std;

// 1. KHOI TAO CAU TRUC NODE
struct Node
{
	int Data;
	Node *pNext;
};

typedef struct Node NODE;


// 2. KHOI TAO CAU TRUC LIST
struct List
{
	NODE* pHead;
	NODE* pTail;
};

typedef struct List LIST;

// KHOI TAO DANH SACH LIST RONG
void CreateEmptyList(LIST &l)
{
	l.pHead = l.pTail = NULL;
}


// TRUYEN DATA VAO NODE
NODE* GetNode(int x) // x la da data can dua vao
{
	NODE *p = new NODE();
	if (p == NULL)
	{
		return NULL; // Khong du bo nho cap phat cho con tro
	}

	p->Data = x;
	p->pNext = NULL;

	return p;

}


// 3. THEM NODE VAO DANH SACH
void addHead(LIST &l, NODE *p)
{
	// NEU DANH SACH RONG
	if (l.pHead = NULL)
	{
		l.pHead = l.pTail = p; // NODE dau va cuoi cua List = p
	}
	else
	{
		// p quang day cho head
		p->pNext = l.pHead;

		// p tro thanh head
		l.pHead = p;
	}
}


void addTail(LIST &l, NODE *p)
{
	// NEU DANH SACH RONG
	if (l.pHead ==NULL)
	{
		l.pHead = l.pTail = p;
	}
	else
	{
		// tail quang day cho p
		l.pTail->pNext = p;

		// p tro thanh tail
		l.pTail = p;

	}
}

// 4. NHAP DANH SACH
void Input(LIST &l)
{
	CreateEmptyList(l);

	int n;
	cout << "\nNhap vao so Node : ";
	cin >> n;

	for (int i = 1; i <= n; i++)
	{
		int x;
		cout << "\nNhap vao data " << i << " : ";
		cin >> x;

		NODE *p = GetNode(x); // Them data vao NODE

		addTail(l, p); // Them Node vao danh sach 

	}
}

void OutPut(LIST l)
{
	for (NODE *p = l.pHead; p != NULL; p = p->pNext)
	{
		cout << p->Data << " ";
	}

}

int TimMax(LIST l)
{
	int Max = l.pHead->Data;
	for (NODE *p = l.pHead->pNext; p != NULL; p = p->pNext)
	{
		if (Max < p->Data)
		{
			Max = p->Data;
		}
	}

	return Max;

}

void HoanVi(int &a, int &b)
{
	int temp = 0;
	temp = a;
	a = b;
	b = temp;
}

void Sort(LIST l, int Option = 1) // Option = 1 : Sap xep tu nho den lon; Option = 2 : Sap xep tu lon den nho 
{

	for (NODE *p = l.pHead; p != NULL; p = p->pNext)
	{
		for (NODE *q = p->pNext; q != NULL; q = q->pNext)
		{
			if (Option == 1)
			{
				if (p->Data > q->Data)
				{
					HoanVi(p->Data, q->Data);
				}
			} else
			{
				if (p->Data < q->Data)
				{
					HoanVi(p->Data, q->Data);
				}
			}
		}
	}
}

int TinhTong(LIST l)
{

	int Tong = 0;
	for (NODE * p = l.pHead; p != NULL; p = p->pNext)
	{
		Tong += p->Data;
	}

	return Tong;
}

void GiaiPhong(LIST l)
{
	NODE *p = new NODE();
	while (l.pHead != NULL)
	{
		p = l.pHead; // cho p bang Head
		l.pHead = l.pHead->pNext; // Cho head tron sang thang ben canh
		delete p;
	}
}

void ThemSau(LIST &l, NODE *p, NODE *q) // Them p vao sau q
{
	for (NODE *k = l.pHead; k != NULL; k = k->pNext)
	{
		if (k->Data == q->Data) // So sanh du lieu
		{
			NODE *g = k->pNext; // Tim duoc q, sau do tim o sau q vd la o g
			k->pNext = p; // q tro next toi p. Khong the dung q->pNext vi luc nay q khong nam trong danh sach lien ket
			p->pNext = g; // p tro next toi g
			return;
		}
	}
}

int main()
{
	LIST l;
	Input(l);
	OutPut(l);
	/*int Max = TimMax(l);
	cout << "\nGia tri lon nhat la : " << Max;
	Sort(l, 2);
	OutPut(l);*/

	/*int p, q;
	cout << "\nNhap vao q : ";
	cin >> q;
	cout << "\nNhap vao p : ";
	cin >> p;
	NODE * P = GetNode(p);
	NODE * Q = GetNode(q);

	ThemSau(l, P, Q);
	OutPut(l);*/

	system("pause");
	return 0;
}
chienbinhthep viết 20:21 ngày 30/09/2018

mình cũng đang xem phần này của a sơn , nếu bạn hiểu rõ thuật toán link list thì mong bạn giúp đỡ.
ở bước thứ 3 trong code của bạn:
//neu danh sach rong
thì lúc này l.phead=p // cái này mình thấy ok rồi
nhưng l.ptail phải bằng null chứ vì sau khi thêm node này vào thì lúc này danh sach moi chi co 1 node mà thôi thì l.ptail=null chứ ?? sao lại bằng p ?

Võ Hoàng Việt viết 20:27 ngày 30/09/2018

Khi danh sách rỗng, nếu bạn thêm vào 1 Node thì trong danh sách lúc bấy giờ chỉ có 1 mình Node đó, hay nói 1 cách dễ hiểu, đầu và cuối của danh sách cũng chính là node đó luôn

chienbinhthep viết 20:15 ngày 30/09/2018

Mình hiểu thế này :lúc đầu khởi tạo một list l.phead=l.ptail=null; tức là lúc này trong danh sách đã có 2 node nhưng 2 node này không có data, cứ gọi là nodedau và nodecuoi; lúc này con trỏ pnext của nodedau này chưa biết trỏ đến đâu nên gán=null và con trỏ pnext cũng chính là con trỏ l.ptail, 2 con trỏ này là một;
còn cái thằng l.ptail sẽ nằm cố định và có giá trị null;
khi thêm 1 node này (node này có data) thì pnext (hay cũng chính là l.ptail) của nodedau sẽ bằng p; còn pnext của node này sẽ bằng l.ptail.
không biết mình hiểu thế có đúng không ?

Võ Hoàng Việt viết 20:21 ngày 30/09/2018

Lúc khởi tạo list rỗng, 2 con trỏ pHead và pTail sẽ được tạo nhưng chưa được cấp pháp vùng nhớ để trỏ tới vì vậy sẽ không có 2 node đầu và node cuối đâu như bạn nói đâu. Node thực sự được tạo ra qua hàm NODE* GetNode(int x), hàm này trả về 1 con trỏ node, dữ liệu kiểu int được truyền qua biến x. Sau đó hàm addHead hay addTail có nhiệm vụ đưa con trỏ vào trong danh sách : lúc này con trỏ mới thực sự nằm trong danh sách nè, bạn để ý chỗ hàm addHead (hoặc addTail) có đoạn code như sau :

if (l.pHead = NULL)
{
	l.pHead = l.pTail = p; // NODE dau va cuoi cua List = p
}

Con trỏ đầu và cuối của list được sẽ bằng p vì danh sách rỗng, nếu danh sách không rỗng thì bạn xem tiếp phần else.
Và cuối cùng, để dễ hiểu, bạn hình dung những công việc mà mình cần làm với list như sau :

  1. Khởi tạo cấu trúc NODE và cấu trúc List (struct)
  2. Tạo 1 list rỗng (createEmptyList)
  3. Truyền data vào node (qua hàm GetNode)
  4. Sau khi có node rồi thì thêm node vào danh sách : thêm đầu hoặc thêm cuối.

Nếu có gì thắc mắc bạn cứ post tiếp nhé

chienbinhthep viết 20:17 ngày 30/09/2018

mình muốn hỏi thêm một chỗ là nếu chỉ tạo 2 node thì ở trong hàm addtail(…)
chỗ else l.ptail->pnext=p;
mình có thể thay bằng lệnh pl.pnext->pnext=p được không ?
vì ở node đầu tiên thì l.phead=l.ptail=p;

chienbinhthep viết 20:14 ngày 30/09/2018

e cảm ơn anh ạ, e cũng bắt đầu hiểu rõ hơn rồi

Võ Hoàng Việt viết 20:26 ngày 30/09/2018

Èo bạn không hiểu rồi, bản chất l.pTail là 1 con trỏ trỏ tới Node cuối, node này chứa 1 con trỏ pNext trỏ tới null. Khi addTail 1 node vào, thì bản thân của node đó sẽ trở thành node cuối (tức là trở thành Tail). Dòng code :

l.pTail->pNext = p
l.pTail = p;

Dòng đầu là cho con trỏ Tail trỏ next tới p (Tail trở thành áp cuối)
Dòng 2 là cho tail là p

Còn bạn nói là thay bằng lệnh p.pnext->pnext = p là không hề có, vì p đang là con trỏ nên sẽ không có toán tử “.” và việc trỏ pnext bằng chính nó không hề đúng (cả về mặt nghĩa cũng như về mặt code). Bạn xem kĩ lại nha

Bài liên quan
0