ヘッドノードのない単一リンクリストL内の値がxであるすべてのノードを削除する再帰アルゴリズムを設計します

この質問は、王道の単著のデータ構造のリンクリストにある授業後の質問の最初の質問で、最初は長い間考えていましたが、理解できませんでした。できませんでした。クラスを読んだ後、答えがわかりませんでした。久しぶりに解決しました。このリンクリストアルゴリズムの問​​題の核となるアイデアは次のとおりです。

タイトルの要件は次のとおりです。

  1. 再帰
  2. リードノードなし

単一リンクリスト内の値がxであるすべてのノードを削除します。通常の線形テーブル削除の場合は、誰でも実行できると思いますが、先頭ノードなしで再帰的に削除する方が頭が痛いです。

最近は比較的時間が短いので、絵を描いて自分の考えを描くには遅すぎます。答えを直接調べてみましょう!

私が書いたコードについて(コメントに注意してください):

/*
1.设计一个递归算法,删除不带头结点的单链表 L 中所有值为 x 的结点 
*/
void RecursionDeleteX(LinkList &L, Element x){
    
    
	if(L == NULL)				//若 L 为空表,则直接进行返回 
		return;
	if(L->data == x){
    
    			//若 L->data 为 x, 则对其进行删除 
		LNode *p = L;		//定义指针变量 p 指向当前结点 
		/*
			非常重要!!!
			该结点指针 L 后移,指向下一结点,注意,由于 L指针为引用数据类型,
			所以L指向结点变化时,它上一层结点的next域也将指向下一结点,这样就可以避免删除操作造成的断链现象 
		*/
		L = L->next;			
		
		free(p);	//此时再将该结点删除 
		RecursionDeleteX(L, x);			//继续递归查找删除子链表中值为 x 的结点 
	}else{
    
    
		RecursionDeleteX(L->next, x);	//结点不是x的话就继续递归下层子链表 
	}
}

  1. 最初のステップは再帰プログラムの終了です。この時点で現在のノードLNULLの場合、単一リンクリスト内のすべてのノードがトラバースされ、値xのすべてのノードの削除操作が完了したことを意味します。呼び出しが返されます。

  2. 2番目のステップでは、ノードがNULLでなく、ノードの値がxの場合、ノードを削除する必要があることを意味します。
    手順を削除する

    (1)削除の準備ができているノードを指す一時的なポインター変数pを定義します。

    (2)。L = L-> next;このステップは非常に重要です。このステップを理解すると、Lポインターを後方に移動して次のノードを指すようにするという、この質問の本質を理解できます。 、リンクリストは切断されますこのノードの接続は、後続のノードを再帰的にトラバースし続ける準備をします。

    このとき、友達の中には疑問があるはずです。L= L-> next、元のLノードが失われるのではないか、チェーンが壊れているのですが、リンクリストでLの後に後継ノードを見つけるにはどうすればよいですか、私も行き詰まりました実際、この操作によってチェーンが切断されることはありません

    その理由は、渡すパラメーターLが参照データ型であり、パラメーターの変更が元の変数の変更であるためです。つまり、このレイヤーのLの変更は自動的にL->に同期されます。前のレイヤーの次へ移動します。つまり、前のレイヤーのL-> nextは、L-> next-> nextも指します。これにより、リンクリストが継続的にチェーンされます。

    (3)free関数を使用してノードを解放します。

    (4)後続ノードをトラバースするために、関数を再帰的に呼び出し続けます。

  3. 3番目のステップでは、ノードがNULLでなく、ノードの値がxでない場合、関数を再帰的に呼び出して、後続のノードをトラバースし続けます。

上記の3つの手順により、再帰メソッドを使用して、単一リンクリストの特定の値削除できます。

実行中のコードのスクリーンショット(データ「5」を削除):
ここに画像の説明を挿入

さて、これはこの質問の私の理解です。私はもともと質問6の単一リンクリストを並べ替え、質問8の単一リンクリストのパブリックノードを書きたかったのですが、時間が足りないので、以下のコードを貼り付けてください。興味のある方は是非ご覧ください!

/*
6.设计一个带头结点的单链表 L , 设计一个算法使其元素递增有序
本题算法思想,将单链表 L 从头部拆分为两个链表,第一个链表初始化仅有一个元素,
故有序,逐渐将第二个链表中的元素插入到第一个链表 L , 使其依旧有序,当全部插入完成后,该链表就实现了排序
类似于 H---->12---->2---->1----->5---->3...... 
L1 = (H---->12---->NULL)				//pre指针作为循环遍历该链表的指针, 用于确定插入位置 
L2 = (2---->1---->5---->3......)		//逐渐将L2的结点按序插入L1即可完成排序, 其中p指向该链表的表头结点, r为p后继结点 
*/
void SortLinkList(LinkList &L){
    
    
	if(L->next == NULL)
		return;
	LNode *p, *pre, *r;			//p 作为 循环遍历链表 L2, pre 作为 循环遍历 L1, r暂存p的后继结点 
	p = L->next;				//实现链表的分割 
	r = p->next;
	p->next = NULL;
	p = r;
	while(p != NULL){
    
    			//循环遍历第二个链表,将其有序插入链表1中 
		r = p->next;
		pre = L;
		while(pre->next!=NULL && pre->next->data < p->data)		//确定插入位置 
			pre = pre->next;
		p->next = pre->next;			//进行插入操作 
		pre->next = p;
		p = r;					// p 指针后移 
	}
}



/*
8.给定两个单链表,编写算法找到两个结点的公共结点 
*/
LinkList GetPublicNode(LinkList &L1, LinkList &L2){
    
    
	if(L1->next==NULL || L2->next==NULL)
		return false;
	int len1 = Length(L1), len2 = Length(L2), dist;
	LinkList short_list, long_list;
	
	if(len1 > len2){
    
    			//确定一个较长的链表和较短的链表,并得到他们的差值 
		long_list = L1->next;
		short_list = L2->next;
		dist = len1-len2;
	}else{
    
    
		long_list = L2->next;
		short_list = L1->next;
		dist = len2-len1;
	}
	
	for(int i=1; i<=dist; i++){
    
    			//根据差值,长链表指针依次后移,目的实现长短链表同步开始寻找公共结点 
		long_list = long_list->next;
	}
	
	while(long_list != NULL){
    
    				//循环遍历寻找公共结点 
		if(short_list->data == long_list->data)
			return long_list;
		short_list = short_list->next;
		long_list = long_list->next;
	}
	return NULL;
}


おすすめ

転載: blog.csdn.net/weixin_43479947/article/details/117640319