1. 程式人生 > >關於遞迴函式非遞迴函式中引用傳參的問題

關於遞迴函式非遞迴函式中引用傳參的問題

首先 我們來看這個函式

typedef int Ele;
typedef struct list{
	Ele data;
	list *next;	
}List,*LNode;
void dele2(LNode &l,Ele e){
	if(l==NULL)return;
	printf("Hello!!\n");
	printf("to %d\n",l);
	if(l->data==e){
		LNode p = l;
		l = l->next;//***
		free(p);
		dele2(l,e);
	}
	
	else dele2(l->next,e);
	printf("back %d\n",l);
}

這個函式就是將連結串列中所有為x的節點全部刪除的操作

但是傳參的時候傳入的是一個指向連結串列節點指標的引用型別 也就是說在其中打***的地方 

不會因為沒有把前面的節點連結到後面而導致斷鏈 相反

這裡的l = l->next 是把當前節點的地址指向了後面

比如對於1 3 1這個連結串列 刪除3操作

第一次走到1 那麼遞迴層數加1時 呼叫dele2(l->next,e); 相當於(*l).next 將該指標所指向的next域的值

取出來並付給更深一層的引數 也就是引用指標&l 那麼在此時在刪除3時

會觸發***處的操作 那麼這裡的操作實質上是 (*l).next = (*(*l).next).next

就相當於直接在1節點的next值修改成了 最後一個節點的地址 也就是相當於整個遞迴過程中對引用指標的操作其實就是對原表

操作

那麼引用就是這樣

在遞迴呼叫的時候 可以直接對原表操作 而且無視可能的斷鏈情況

再來看一個函式


void delehead(LNode &p,Ele x){

	while(p!=NULL){		
		if(p->data == x){
			LNode q = p;
			p = p->next;
		//	pre->next = p;
			free(q);
		}
		else {
		//	pre = p;
			p = p->next;			
		}
	}
}

相同的操作 就是把遞迴改成非遞迴了 相同的是引用 但是這種情況下 就會導致斷鏈

因為當在遞迴中使用引用的過程時 遞迴結束時會把一層層加上的取值操作符再把取值操作符一層層摘掉

而這裡卻是讓p不斷指向next 指到最後變成空 因為這裡沒有遞迴函式中返回的操作

1 3 1中執行結束的時候 遞迴不斷返回後 原指標指向的是首節點 

而非遞迴中由於沒有返回操作 會不斷地讓頭指標所指向的值一直向後走 最後使頭指標

指到最後的NULL處

所以應另外使用指標非指標引用 這樣不會修改原表的地址 並且附加前後連結操作

如果為了防止首元素刪除導致頭指標找不到首節點 應該另外設定頭結點 或者 用計數另外記錄下修改後頭指標

應指向的位置 所以應改為

void delehead(LNode &l,Ele x){
    // l指向頭結點
	LNode p = l->next,pre = l;
	// p指向頭節點的後繼節點 pre指向頭節點 
	// no head node
	while(p!=NULL){		
		if(p->data == x){
			LNode q = p;
			p = p->next;
			pre->next = p;
			free(q);
		}
		else {
			pre = p;
			p = p->next;			
		}
	}
}

這樣就處理了非遞迴情況下對連結串列中刪除任意位置值為x的操作 如果這裡用頭指標的單鏈表

會可能導致由於第一個節點的釋放從而頭指標指向了一個釋放記憶體的地址

相關推薦

關於函式函式引用的問題

首先 我們來看這個函式 typedef int Ele; typedef struct list{ Ele data; list *next; }List,*LNode; void dele2(LNode &l,Ele e){ if(l==NULL)ret

分別採用方式編寫兩個函式,求一棵二叉樹葉子節點個數

#include #include #define MAXSIZE 50 typedef char datatype; typedef struct node { datatype data; struct node *lchild,*rchild; } bintnode,*bintre

hanoi塔的以及函式

/** * @file Hanoi.c * @brief * <li>Function: Hanoi塔的遞迴以及非遞迴解法</li> * <li>Design Points:</li> * <p>

某些函式實現的比較

1.斐波那契數列實現~   遞迴實現: int fib(int n) { if (n == 1 || n == 2) return 1; else return fib(n - 1) +

二叉樹的先序/序/後序()+層序遍歷

queue 的基本操作舉例如下: queue入隊,如例:q.push(x); 將x 接到佇列的末端。 queue出隊,如例:q.pop(); 彈出佇列的第一個元素,注意,並不會返回被彈出元素的值。 訪問queue隊首元素,如例:q.front(),即最早被壓入佇列的元素。 訪問que

二叉樹的前序,序,後序的遍歷的程式碼-C語言

#include <stdio.h> #include<stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input l

二叉樹的前後序遍歷(版本)

各位讀者週末愉快呀,今天我想來說說一道很常見的面試題目 —— 關於二叉樹前中後序遍歷的實現。本文將以遞迴和非遞迴方式實現這 3 種遍歷方式,程式碼都比較短,可以放心食用。 先簡單說明一下這 3 種遍歷方式有什麼不同 —— 對於每種遍歷,樹中每個結點都需要經過 3 次(對於葉結點,其左右子樹視為空子樹),但前

樹的前、、後序遍歷演算法()、層序遍歷

二叉樹層次遍歷 非遞迴 void LevelOrder(Tree* T) { if(T == nullptr) return ; queue<Tree *> myqueue; myqueue.push(T); while(!myqueu

c++二叉樹的的前序序和後序遍歷以及層序遍歷

二叉樹的遞迴版的前序,中序和後序遍歷很簡單也很容易理解,這裡就放一個前序遍歷的例子 //前序遍歷遞迴演算法,遞迴演算法都大同小異,這裡就不一一列舉了 void binaryTree::pro_order(NodeStack::Node *t) { NodeStack::Node *h = t;

二叉樹的序遍歷-演算法

建立二叉樹就不說了,這裡直接: 中序遞迴遍歷演算法 void InOrder(BiTree T){ if(T){ InOrder(T->lchild); cout<<T->data<<" "; InOrder(T->rch

序遍歷--(java版)

根據中序遍歷的順序,對於任一結點,優先訪問其左孩子,而左孩子結點又可以看做一根結點,然後繼續訪問其左孩子結點,直到遇到左孩子結點為空的結點才進行訪問,然後按相同的規則訪問其右子樹。因此其處理過程如下:   對於任一結點root,引入一個輔助節點p,其作用是:標記已經訪問過的節點, &nb

鏈式二叉樹 先序、序、後序 遍歷(

參考部落格:click here! 鏈式二叉樹儲存結構: typedef int DataType; typedef struct BiNode { DataType data; struct BiNode *lc, *rc; // 左右子節點指標 int depth; } B

Leetcode---序遍歷二叉樹--

中序遍歷二叉樹 題目連結:中序遍歷二叉樹 解法一: 遞迴遍歷比較簡單 public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayLi

樹的遍歷--樹的廣度遍歷(層次遍歷),深度遍歷(前序遍歷,序遍歷,後序遍歷的實現)

一 由於本人的碼雲太多太亂了,於是決定一個一個的整合到一個springboot專案裡面。 附上自己的github專案地址 https://github.com/247292980/spring-boot 附上彙總博文地址 https://www.cnblogs.com/ydymz/p/9391653.h

二叉樹的前序,序,後序遍歷。用實現

#include<iostream> #include<stack> using namespace std; #define MAX 100 typedef struct Tree{ int data; Tree*lchild; Tree*rchild; }

求二叉樹葉子結點的個數(的方式實現)

思路: (1)通過先序遍歷的方式求解 (2)葉子節點的特點: 左右孩子都為空 可以用非遞迴的方式 也可以用遞迴方式  package com.zhaochao.tree; import java.util.Stack; /** * Created by z

二叉樹的序遍歷(版本)

轉自來自微信公眾號,一個專注應屆生網際網路求職分享的公眾號,公眾號ID:“菜鳥名企夢” 難易程度:★★ 重要性:★★★★★ 樹結構是面試中的考察的重點,而樹的遍歷又是樹結構的基礎。中序遍歷的非遞迴版本要求重點理解掌握。 //先序遍歷,遞迴版本 public stati

二叉樹——前、、後序遍歷以及寫法

#include <iostream> #include <stack> #include <queue> using namespace std; typedef struct Node{ int data; Node *l

二叉樹遍歷:前序,序,後序,層序的以及實現

樹,是一種在實際程式設計中經常遇到的資料結構,它的邏輯很簡單:除根節點之外每個節點都有且只有一個父節點,除葉子節點之外所有節點都有一個或多個子節點。我們說的二叉樹,就是指子節點最多2個的樹。 二叉樹中,最重要的操作就是遍歷。二叉樹的遍歷分為: 1.前序遍歷:先訪問根節點,

Java資料結構:二叉樹的前序,序,後序遍歷(

嚶嚶嚶,兩個月沒寫部落格了,由於有點忙,今天開始日更部落格。 今天總結一下學習樹的先根,中根,後根。每種兩種方法,遞迴和非遞迴。 先根: 遞迴: 思路:先根遍歷,即第一次遇到的結點就開始列印。先一直遍歷左子樹,直到未空,然後右子樹,直到為空。遞迴下去。 過程:先將1進入方法