1. 程式人生 > >【c/c++】單鏈表、頭指標、頭結點、首元節點

【c/c++】單鏈表、頭指標、頭結點、首元節點

連結串列中第一個結點的儲存位置叫做頭指標,那麼整個連結串列的存取就必須是從頭指標開始進行了。之後的每一個結點,其實就是上一個的後繼指標指向的位置。

這裡有個地方要注意,就是對頭指標概念的理解,這個很重要。“連結串列中第一個結點的儲存位置叫做頭指標”,如果連結串列有頭結點,那麼頭指標就是指向頭結點資料域的指標。畫一個圖吧。

頭指標就是連結串列的名字。頭指標僅僅是個指標而已。

  • 頭結點是為了操作的統一與方便而設立的,放在第一個元素結點之前,其資料域一般無意義(當然有些情況下也可存放連結串列的長度、用做監視哨等等)。
  • 有了頭結點後,對在第一個元素結點前插入結點和刪除第一個結點,其操作與對其它結點的操作統一了。
  • 首元結點也就是第一個元素的結點,它是頭結點後邊的第一個結點。
  • 頭結點不是連結串列所必需的。
  • 是的,對於頭指標,我們也可以有相應的理解了。
  • 線上性表的鏈式儲存結構中,頭指標是指連結串列指向第一個結點的指標,若連結串列有頭結點,則頭指標就是指向連結串列頭結點的指標。
  • 頭指標具有標識作用,故常用頭指標冠以連結串列的名字
  • 無論連結串列是否為空,頭指標均不為空。頭指標是連結串列的必要元素。
  • 單鏈表也可以沒有頭結點。如果沒有頭結點的話,那麼單鏈表就會變成這樣:
//這裡插入關於連結串列中有無頭節點進行初始化連結串列知識
//首先明白頭指標與頭結點的關係:http://www.nowamagic.net/librarys/veda/detail/1805
//定義結點的結構體
//typedef struct LNode{
//	int data;
//	struct LNode *next;
//}LNode,*LinkList;//則定義LinkList L;時,L為連結串列的頭指標。
//
//L=(LinkList) malloc (sizeof(LNode)); //建立一個結點,此處返回給L的是一個指標,並且賦給了頭指標。
//L->next=null; //這裡說明我建立了一個頭結點,即同時運用了頭指標和頭結點。
//這麼方便只要加上->next就說明建立了頭節點。不過你想想頭指標是沒有next的,只有頭結點才有,所以就不難理解了


//帶頭結點初始化
//Node *head;  //宣告頭結點
//首先第一眼看到(*head)->next=NULL;和我們剛才所說是不是一樣,只要頭指標一旦運用了next操作就自動建立了頭結點
//但是我們今天的重點不在於這個,更多在於Node **head,對於兩個指標的操作理解
//第一個指標*head,表明了head這個指標變數儲存的是另外一個指向結構體NODE的指標,第二個指標,即*head作為一個整體
//其結果是一個指標,其指向的內容就是結構體NODE。經過這麼一理解,對於頭指標,頭結點,首元節點的關係就非常明朗了
//	void InitList(Node **head){
//		*head=(Node *)malloc( sizeof(Node));//這裡需要明確的第一點,申請記憶體返回的都是地址
//		//第二點就是(Node *)表明了其返回的指標指向最後的結果是NODE的結構體,如果是指向int,那麼我們就寫(int *)
//		(*head)->next=NULL;
//}


//帶頭結點尾方便了首元節點和其他節點一樣,統一了操作
	//方式一:
//	void CreatList(Node **head){
//		Node *r=*head,*s;//因為前面已經對頭結點,頭指標初始化過了,因此可以直接使用*head
//		int a;
//		while(scanf("%d",&a)){
//			if(a!=0){
//				s=(Node *)malloc(sizeof(Node));
//				s->value=a;
//				r->next=s;//這裡沒有著急設定s->next,原因在於後續還要插入資料。因此將s賦值給r
//				r=s;    
//			}
//			else{    
//				r->next=NULL;//如果後續輸入的資料為空,則就將其設定為null
//				break;    
//			}
//		}
//}
//呼叫CreatList(&head);//這句話表明了形參Node **head,只有第一個*才是起作用了,第個*號是和head聯絡在一起,作為整體使用的


//方式二:
//	void CreatList(Node *head){
//		Node *r=head,*s;
//		... //下面的都一樣
//}
//呼叫CreatList(head);
//

//不帶頭結點初始化
//方式一:
//void InitList(Node **head){
//		*head=NULL;//這裡直接就是指向的首元節點,還有之前自己一個誤解,看到head就覺得它就是頭指標了,其實它就是隨便一個指標變數
         //並不是像自己之前想的那樣的


		//從這裡才發現,真正有無頭節點的區別。
		//*head=(Node *)malloc( sizeof(Node));//這裡需要明確的第一點,申請記憶體返回的都是地址
		//第二點就是(Node *)表明了其返回的指標指向最後的結果是NODE的結構體,如果是指向int,那麼我們就寫(int *)
		//(*head)->next=NULL;
//}
//呼叫InitList(&head);
//
//方式二:
//void InitList(Node *head){
//		head=NULL;
//}
//呼叫InitList(head);

//不帶頭結點尾插入,第一個節點與其他節點分開操作
//void CreatList(Node  **head){
//		Node *p,*t;         /*p工作指標,t臨時指標*/
//		int a,i=1;
//		while(scanf("%d",&a)){
//			if(a!=0){
//				t=(Node *)malloc(sizeof(Node));
//				t->value=a;
//				if(i==1){
//					*head=t;    
//				}
//				else{
//					p->next=t;
//				}
//				p=t;
//			}
//			else{    
//				p->next=NULL;
//				break;    
//			}
//			i++;
//		}
//}
//呼叫CreatList(&head);
//其實從上面就可以知道,其實有頭結點對於我們來說是一種更加明智更加方便的操作


一、兩者區別:      1、不帶頭結點的單鏈表對於第一個節點的操作與其他節點不一樣,需要特殊處理,這增加了程式的複雜性和出現bug的機會,因此,通常在單鏈表的開始結點之前附設一個頭結點。  2、帶頭結點的單鏈表,初始時一定返回的是指向頭結點的地址,所以一定要用二維指標,否則將導致記憶體訪問失敗或異常。 這點就是指標方面的知識點了。不懂了就回去好好看一下指標      3、帶頭結點與不帶頭結點初始化、插入、刪除、輸出操作都不樣,在遍歷輸出連結串列資料時,帶頭結點的判斷條件是while(head->next!=NULL),而不帶頭結點是while(head!=NULL),雖然頭指標可以在初始時設定,但是如1所述,對於特殊情況如只有一個節點會出現問題。
二、為什麼不帶頭結點初始化有2種方式,而帶頭結點只有1種方式呢? 因為不帶頭結點宣告Node *head 時;C編譯器將其自動初始化為NULL,於是根本不需要呼叫InitList(head);也即不帶頭結點的初始化是個偽操作。而帶頭結點的初始化在堆開闢了一段記憶體,需要修改head指標變數指向的地址(即head的值),所以要修改head的值,必須傳保存head變數的地址(即二維指標)。而直接呼叫CreatList(head);相當於傳head變數的值,函式修改的是head的副本,無法真正改變head的值。  其實這個就是上面所說的第二點內容 、其實本質上還是傳值,傳址的問題,只不過指標本身儲存的地址,讓這個過程變得有點糾結。在函式呼叫需要修改指標變數的指向(value)時,應該傳遞指標變數的地址(address)。       另外,對於函式的形參是指標時,只要該引數不在左邊(即都是右值操作),二維指標(形參)就可以簡化為一維指標。如上面帶頭結點的尾插簡化版本。

相關推薦

C語言單鏈的實現

單鏈表 單鏈表是一種鏈式存取的資料結構,用一組地址任意的儲存單元存放線性表中的資料元素。 單鏈表結構如下: typedef int DataType; typedef struct Node { struct Node* next; /

資料結構單鏈的實現與基本操作C++

最近在複習資料結構,自己用C++寫了單鏈表這一塊的一些程式碼。 以下是帶頭結點單鏈表的建立和查詢等的程式碼。 #include <iostream> using namespace std; //單鏈表 struct LNode{ int data; st

資料結構單鏈的應用(C語言)

1、設計一個演算法,求一個單鏈表中的節點數 2、設計一個演算法,在一個單鏈表中值為y的結點前插入一個值為x的結點(值為x的新結點為成為值為y的結點前驅結點) 3、設計一個演算法,判斷單鏈表中各結點是否有序 4、設計一個演算法,利用單鏈表中原來的結點空間逆轉一個單鏈表

資料結構單鏈的逆序輸出

即:將一個已經建立好的單鏈表進行指標域的改變 今天突然被問到單鏈表逆序的問題,弄了好久才看出別人的程式有啥問題,就重新寫了一遍。 今天才在CSDN客戶端上看到美團的面試題是氣泡排序。 一個看似簡單的問題難倒很多人,所以簡單的不要因為他簡單就忽視它,人們在簡單的問題上越容易犯錯!

資料結構單鏈的實現

單鏈表是線性錶鏈式儲存的一種形式,其中的結點一般含有兩個域,一個是存放資料資訊的info域,另一個是指向該結點後繼結點存放地址的指標next域。一個單鏈表必須要有一個首指標指向連結串列中的第一個結點。 單鏈表要掌握以下幾種操作: 1、建立一個空的單鏈表。 2、輸出單鏈表

資料結構單鏈-----基本操作

刪除指定位置的節點 void Erase(pList * pplist, pNode pos) { assert(pplist != NULL); assert(pos != NULL); if (*pplist == pos)//如果指向第一個節點

資料結構單鏈(無頭單向非迴圈連結串列)各個介面的實現

順序表存在的問題: 中間/頭部的插入刪除,時間複雜度為O(N) 增容需要申請新空間,拷貝資料,釋放舊空間。會有不小的消耗 增容一般是呈2倍的增長,勢必會有一定的空間浪費。 例如當前容量為100,滿了以後增容到200,如果再繼續插入了5個數據,後面沒有資料插入了,

資料結構單鏈的運用 多項式加法

#include<stdio.h> #include<stdlib.h> struct mono{     int e;     int c; }; struct node{     mono data;     node * next; }; str

程式設計2單鏈+單鏈反轉(LeetCode. 206)

文章目錄 一、連結串列 二、單鏈表 1、基本概念 (1)單鏈表 (2)頭指標——必有元素 (3)頭結點——非必需元素 (4)尾結點 2、查詢操作

資料結構單鏈

我們單鏈表是一種鏈式存取的資料結構,用一組地址任意的儲存單元存放線性表中的資料元素。連結串列中的資料是以結點來表示的,每個結點的構成:元素(資料元素的映象) + 指標(指示後繼元素儲存位置),元素就是儲存資料的儲存單元,指標就是連線每個結點的地址資料。 我們

資料結構單鏈—逆置單鏈

題目:定義一個函式,輸入一個連結串列的頭結點,反轉該連結串列並返回反轉連結串列後的頭結點。 我們可以藉助圖來分析一下: 我們定義一個新的頭結點為head,將begin指向head->_next,當begin不為空的時候,tmp = begin,be

資料結構單鏈迴圈左移K位

例如連結串列資料有:1 2 3 4 5 6 7 8 910 左移2位 結果為 3 4 5 6 7 8 9 10 1 2 需要處理邊界情況 :左移11位 顯示錯誤 ,左移0位 顯示錯誤 ,左移10位 顯示錯誤。 void leftshift(LinkList List,

c/c++單鏈指標結點節點

連結串列中第一個結點的儲存位置叫做頭指標,那麼整個連結串列的存取就必須是從頭指標開始進行了。之後的每一個結點,其實就是上一個的後繼指標指向的位置。 這裡有個地方要注意,就是對頭指標概念的理解,這個很重要。“連結串列中第一個結點的儲存位置叫做頭指標”,如果連結串列有頭結

C++/數據結構單鏈的基本操作

clear default als troy pub 插入 else fonts pac #pragma once #ifndef _CLIST_H_ #define _CLIST_H_ #include <iostream> #include <

C#資料結構-從零開始單鏈

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp8 {

C/C++單鏈的倒置

(程式碼在末尾) 設有連結串列 head->1->2->3... 可用頭插法將其倒置,具體步驟為: 1.建立指標p,t均指向head->next,p表示正在的節點,t表示待處理的節點 2.將head->next置為空,即NULL 3.若p指標為空,跳

C單鏈的簡單實現和應用!!!

在單鏈表裡面,每個節點包含一個指向下一個節點 的指標。連結串列的最後一個節點的指標欄位是一個值為NULL的指標,他的作用就是提示連結串列後面不再有其他的節點。在你找到連結串列的第一個節點的時候呼叫節點裡面的指標就可以依次訪問剩下所有的節點。為了記住連結串列的起始位置,可以用

C++類中單鏈的實現(尾插尾刪指定位置插入指定位置刪除連結串列長度清空連結串列連結串列排序)

#include<iostream> using namespace std; class Node { public:Node():next(NULL){}Node(int n,Node *p = NULL):value(n),next(p){}int val

C語言寫單鏈的創建釋放追加(即總是在最後的位置增加節點

程序 mage 而不是 自己的 物理 2-66 exit 只為 對數 昨天周末給學妹講了一些指針的知識,本來我對指針就是似懂非懂的狀態,經過昨天一講,我對指針的學習就更深刻了果然給別人講課也是學習的一個方法。加上最近復習數據結構,發現我的博客裏沒有鏈表的博文,

C語言》單鏈——增銷燬排序翻轉合併取中間節點...

《C語言》單鏈表——增、刪、查、改、銷燬、排序、翻轉、合併、取中間節點... Main.c S_List.h S_LIst.c Main.c #include "S_List.h" #include <time.h> v