データ構造の復習 (7) テンプレートクラスカプセル化によるヘッドノードのない単方向リンクリストの実現

1. コード

2. まとめ


1. コード


#include<iostream>
using namespace std;

template<class T>
struct ListNode
{
	T _data;
	ListNode* next;
	ListNode(const T& data = T())
	{
		_data = data;
		next = nullptr;
	}
	~ListNode()
	{
		next = nullptr;
	}
};

template<class T>
class List
{
	typedef ListNode<T> Node;    // 重命名
public:
	List()
	{
		_head = nullptr;
	}
	void PushFront(const T& data = T())    // 每次对头结点判空处理
	{
		Node* newnode = new Node(data);
		if (_head == nullptr)
			_head = newnode;
		else
		{
			Node* cur = _head;
			_head = newnode;
			_head->next = cur;
		}
	}
	void PopFront()
	{
		if (_head == nullptr)
			return;
		Node* del = _head;
		_head = _head->next;
		delete del;
	}
	void PushBack(const T& data = T())
	{
		Node* newnode = new Node(data);
		if (_head == nullptr)
		{
			_head = newnode;
			return;
		}
		Node* cur = _head;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
	void PopBack()
	{
		Node* pre = _head;
		if (pre == nullptr)
			return;
		else if (pre->next == nullptr)
		{
			_head = nullptr;
			delete pre;
		}
		else
		{
			Node* cur = _head->next;
			while (cur->next)
			{
				cur = cur->next;
				pre = pre->next;
			}
			pre->next = nullptr;
			delete cur;
		}
	}
private:
	Node* _head;
};

void Test()
{
	List<int> l;
	l.PushBack(0);
	l.PushBack(1);
	l.PushBack(2);
	l.PushBack(3);
	l.PushBack(4);
	l.PopBack(); 
	l.PopBack(); 
	l.PopBack();
	l.PopBack();
	l.PopBack();
	l.PopBack();
	l.PopBack();
}

void Test1()
{
	List<int> l;
	l.PushFront(0);
	l.PushFront(1);
	l.PushFront(2);
	l.PushFront(3);
	l.PushFront(4);
	l.PopFront();
	l.PopFront();
	l.PopFront();
	l.PopFront();
	l.PopFront();
	l.PopFront();
	l.PopFront();
}

2. まとめ

 先頭ノードのある単連鎖リストと先頭ノードのない単連鎖リスト
1. 2 つの違い:

1. 先頭ノードのない単連鎖リストの操作は、最初のノードに対する他のノードの操作とは異なります。特別な処理により、プログラムが複雑になり、バグが発生する可能性が高くなるため、通常、ヘッド ノードは単方向リンク リストの開始ノードの前に接続されます。

2. 先頭ノードを持つ単一リンク リストの場合、最初に先頭ノードを指すアドレスを返す必要があるため、2 次元ポインタを使用する必要があります。そうしないと、メモリ アクセスの失敗または例外が発生します。

3. 先頭ノードと非先頭ノードの初期化、挿入、削除、出力操作が異なる 出力連結リストデータをたどる際、先頭ノードの判定条件は while(head->next!=NULLノードはwhile(head!=NULL)ですが、最初はヘッドポインタを設定できますが、1で述べたように、ノードが1つしかないなどの特殊な場合に問題が発生します。

2. 非リーディング ノードを初期化する方法が 2 つあるのに、リーディング ノードを初期化する方法が 1 つしかないのはなぜですか? Node *head が

ヘッド ノードなしで宣言されると、C コンパイラが自動的にそれを NULL に初期化するため、InitList(head) を呼び出す必要はありません; つまり、ヘッド ノードなしの初期化は疑似操作です。リーディング ノードの初期化により、ヒープ内のメモリのセクションが開かれ、ヘッド ポインター変数が指すアドレス (つまり、ヘッドの値) を変更する必要があります。したがって、ヘッドの値を変更するには、ヘッド変数 (つまり、2 次元ポインター) のアドレスを渡す必要があります。CreatList(head); を直接呼び出すことは、 head 変数の値を渡すことと同じです. 関数は head のコピーを変更し、 head の値を実際に変更することはできません. 注: ここでは、理解しやすいように、ヘッド ポインターを (保持するアドレスに関係なく) 変数と見なすことができます。3. 実際には、本質的には値の受け渡しとアドレスの受け渡しの問題ですが、ポインター自体によって保存されるアドレスにより、このプロセスが少し複雑になります。関数呼び出しでポインター変数のポインティング (値) を変更する必要がある場合は、ポインター変数のアドレス (アドレス) を渡す必要があります。





また、関数の仮パラメータがポインタの場合、パラメータが左辺でない限り(つまり、右辺値演算でない限り)、2次元ポインタ(仮パラメータ)を1に簡略化できます。 -次元ポインター。テール プラグの簡略化されたバージョンで、先頭ノードが上にあります。


名前空間 std を使用する#include<iostream>
;

template<class T>
struct ListNode
{     T _data;     ListNode* 次;     ListNode(const T& データ = T())     {         _data = データ;         次 = nullptr;     }     ~ListNode()     {         次 = nullptr;     } };











template<class T>
class List
{     typedef ListNode<T> ノード; public:     List()     {         _head = nullptr;     }     void PushFront(const T& data = T())     {         ノード* newnode = 新しいノード(データ);         if (_head == nullptr)             _head = newnode;         else         {             ノード* cur = _head;             _head = 新しいノード;             _head->next = cur;         }     }     void PopFront()     {         if (_head == nullptr)             return;         ノード* del = _head;























        _head = _head->next;
        デルを削除します。
    }
    void PushBack(const T& data = T())
    {         ノード* newnode = 新しいノード(データ);         if (_head == nullptr)         {             _head = newnode;             戻る;         }         Node* cur = _head;         while (cur->next)         {             cur = cur->next;         }         cur->next = newnode;     }     void PopBack()     {         Node* pre = _head;         if (pre == nullptr)             return;         else if (pre->next == nullptr)



















        {             _head = nullptr;             前を削除します。         }         else         {             ノード* cur = _head->next;             while (cur->next)             {                 cur = cur->next;                 pre = pre->next;             }             pre->next = nullptr;             cur を削除します。         }     }プライベート:     Node* _head; };

















void Test()
{     List<int> l;     l.PushBack(0);     l.PushBack(1);     l.PushBack(2);     l.PushBack(3);     l.PushBack(4);     l.PopBack();     l.PopBack();     l.PopBack();     l.PopBack();     l.PopBack();     l.PopBack();     l.PopBack(); }













void Test1()
{     List<int> l;     l.PushFront(0);     l.PushFront(1);     l.PushFront(2);     l.PushFront(3);     l.PushFront(4);     l.PopFront();     l.PopFront();     l.PopFront();     l.PopFront();     l.PopFront();     l.PopFront();     l.PopFront(); }













おすすめ

転載: blog.csdn.net/weixin_66151870/article/details/129110224