1. 程式人生 > >C語言 有序雙鏈表實現插入、刪除、列印(正反)等簡單操作

C語言 有序雙鏈表實現插入、刪除、列印(正反)等簡單操作

1.雙鏈表與單鏈表的區別主要是在於雙鏈表中,每個節點都包含兩個指標——指向前一個節點的指標,和指向後一個節點的指標。這就便於我們從任何方向遍歷整個連結串列。

下面是節點型別的說明:

typedef struct NODE{
	struct NODE *fwd;
	struct NODE *bwd;
	int value;
}Node;
構造了一個簡單的連結串列節點,此時,我們需要兩個根指標,一個指向連結串列的第一個節點,另一個指向連結串列的最後一個節點。

我們可以考慮為根指標宣告一個完整的節點,但應該注意其value欄位不被使用,我們僅僅是用該節點來表示根指標,其並不存在於連結串列之中,我們讓rootp->fwd表示連結串列第一個節點,而rootp->指向連結串列最後一個節點,這就需要在main函式中為該節點分配空間,且初始化rootp->fwd以及rootp->bwd為NULL。

Node *rootp; 
rootp=(Node *)malloc(sizeof(Node)); //為根指標分配空間,並初始化連結串列第一部分為NULL 
	rootp->bwd=NULL;
	rootp->fwd=NULL;
這時可以在專門的free函式中釋放該空間,也可以在main函式最後釋放。

2.實現值的有序插入

這時需要考慮節點插入的位置,一般來講有4種情況:

1.插入位置在連結串列中間段;

2.插入位置在連結串列初始段;

3.插入位置在連結串列尾部;

4.該連結串列為空連結串列;

需要分別考慮這4種不同情況下節點的fwd及bwd指標指向。

以下程式碼詳細描述了這四種情況下的指標指向:

if(next!=NULL)              //四種情況 
	{                             //1.中間 2.起始 3.末尾 4.空 
		if(this!=rootp)           //1.中間 
		{
			newnode->fwd=next;
			this->fwd=newnode;
			next->bwd=newnode;
			newnode->bwd=this;
		}
		else{                   //2.初始 
			newnode->fwd=next;
			rootp->fwd=newnode;
			newnode->bwd=NULL;
			next->bwd=newnode;
		}
	}
	else{                      
		if(this!=rootp)         //末尾非空 
		{
			newnode->fwd=next;
			this->fwd=newnode;
			newnode->bwd=this;
			rootp->bwd=newnode;
		}
		else{                   //空 
			newnode->fwd=NULL;
			rootp->fwd=newnode;
			newnode->bwd=NULL;
			rootp->bwd=newnode;
		}
	}


同時,我們可以注意到以上單純實現插入的程式碼段比較冗餘,由於if語句內有功能相似或相同的程式碼,我們可以將其提取出現,減少程式碼量。

比如每個if語句中都有newnode->fwd=next,以及this->fwd=newnode.且在程式執行到該段時,newnode及this指標一定不為NULL,故可以直接提取出來。如下是改進後的完整的插入節點的程式碼段。

ps:注意到根指標rootp的儲存空間是在main函式中通過malloc語句分配,儲存在堆(heap)中,在做插入、刪除等系列操作時,並不需要改變rootp的值,故在函式引數列表中並不需要像單鏈表頭指標一樣傳入其地址(當然,傳地址也是可以的)。

這裡是直接將rootp的值傳入到函式中。

int dll_insert(Node *rootp,int num)
{
	Node *next;     //插入位置的下一個 
	Node *this;    //插入位置的前一個 
	Node *newnode;
	
	//	for(this=rootp;(next=this->fwd)!=NULL;this=next)
	for(this=rootp,next=rootp->fwd;next;this=next,next=next->fwd) //尋找插入位置,從頭開始 
	{
		if(next->value==num)   //插入不同數 
			return 0;
		else if(next->value>num)  //一旦找到比待插入數大的位置,跳出迴圈; 
			break;	
	}
	
	newnode=(Node *)malloc(sizeof(Node)); //為新插入的節點分配空間 
	if(newnode==NULL) 
		return -1;
	newnode->value=num;	
	newnode->fwd=next;        //以下是實現插入(簡化版) 
	this->fwd=newnode;
	
	if(this!=rootp)          //非初始 
	{
		newnode->bwd=this;
	}
	else{                   //初始 
		newnode->bwd=NULL;
	}
	if(next!=NULL)          //非結尾 
	{
		next->bwd=newnode;
	}
	else{                   //結尾(新加入的節點在最後一個位置) 
		rootp->bwd=newnode;
	}
	
	return 1;
} 

3.刪除節點

在刪除某個節點時,需要注意刪除的位置是在初始位置,中間位置,還是末尾位置,同時需注意刪除之後連結串列是否為空。

void reduce(Node *rootp)  //刪除 
{
	Node *q,*p,*t;   //t可以木有√ 
	int isFound=0;  //標記是否找到 
	int num;
	puts("Please enter the num to delete:");
	scanf("%d",&num);
	while(getchar()!='\n')
		continue;
		
	for(q=NULL,p=rootp->fwd;p;q=p,p=p->fwd)  //刪除
	{
		if(p->value==num)   //如果找到了 
		{
			isFound=1;
			if(q)       
			{
				q->fwd=p->fwd; //
				if(p->fwd==NULL) //最後位置 
				{
					rootp->bwd=q; //表示q位置為最後一個,刪除p; 
				}
				else{
				//	t=p->fwd; //p->fwd->bwd=q;
					p->fwd->bwd=q;   //不是最後一個,刪除p,p的後一個的前一個為q 
				}
			}
			else{
				rootp->fwd=p->fwd;  //q為NULL,那麼p是第一個,刪除p,根指標指向第二個(可能為空,這樣整個連結串列就是空的了),現在是第一個了 
				if(p->fwd==NULL)  //p是最後一個。說明刪除之後就沒有了 
					rootp->bwd=NULL;  //整個連結串列為空, rootp->bwd=NULL   rootp->fwd=p->fwd,而p->fwd為空 
				else{
					p->fwd->bwd=NULL;//這個意思是p後面還有,那麼該節點為第一個了,其bwd要指向NULL; 
				} 
				 
			}
			free(p);
			break;
		}
	}
	if(!isFound)
	{
		printf("Not found.\n");
	}
}
3.正向列印及反向列印

這個操作比較簡單,不多做介紹。

void print(Node *rootp)  //列印 
{
	Node *p;
	for(p=rootp->fwd;p;p=p->fwd)  //正向列印,以根指標的初始指向為開始,以連結串列初始節點開始 
	{
		printf("The num is %d.\n",p->value);
	}	
}

void bkprint(Node *rootp)  //反向列印 
{
	Node *p;
	for(p=rootp->bwd;p;p=p->bwd)  //反向列印,以根指標的bwd為始,指向的是連結串列最後一個節點 
	{
		printf("The num is %d.\n",p->value);
	}	
}




相關推薦

C語言 有序實現插入刪除列印正反簡單操作

1.雙鏈表與單鏈表的區別主要是在於雙鏈表中,每個節點都包含兩個指標——指向前一個節點的指標,和指向後一個節點的指標。這就便於我們從任何方向遍歷整個連結串列。 下面是節點型別的說明: typedef

C語言 連結串列的建立,插入刪除列印

#include <stdio.h> #include <stdlib.h> #include <memory.h> //結構體定義 struct Node{ char name[10]; int score; s

朱有鵬C語言高階---4.9.10----頭插入和尾插入10

朱有鵬C語言高階---4.9.10--雙鏈表--頭插入和尾插入(10)   尾插入:   頭插入:   注意下面的程式碼中,insert_head()函式裡面語句的順序,第一語句和第二語句的順序可以互相調換,但是第一語句和第二語句要在

C++插入刪除

pac out 當前 include intall streams 新節點 repair 節點 #include<iostream>#include<limits>using namespace std;class Date{public: Date

C++資料結構

《資料結構》實驗二:                 線性表綜合實驗 一.實驗目的  &nbs

實驗三 用實現學生成績管理系統

#include<iostream> using namespace std; //template<class DataType> typedef int DataType; struct Node { DataType data; struct Node *next;

Go語言(Golang)

package main import ( "fmt" ) //雙鏈表結構 type TwoLinkTable struct { no int name string pre *TwoLinkTable next *TwoLinkTable } //直接在隊尾插入 func Inser

C語言:用單鏈實現輸入排序

純當練習 連結串列頭結點儲存的資訊是連結串列長度 平臺VS2015 #include<stdio.h> #include<stdlib.h> #include<time.h> struct ListNod

數據結構C語言循環練習之俄羅斯輪盤賭

lis c語言 sed time tchar 分享圖片 技術分享 頭指針 node 編譯器: /******************************project :數據結構*function :循環鏈表之俄羅斯賭盤*Author :Rook

C語言反轉單向的代碼

clu 應該 eve else int test rev var for 學習過程中中,把內容過程中常用的內容片段做個珍藏,下邊內容段是關於C語言反轉單向鏈表的內容,應該能對大夥有較大用處。 #include "stdafx.h" enum{N = 3}

寒假 12 實現徹底結束,find kth未解決

移動 中間變量 順序 編譯 默認 想要 改變 元素操作 ins 表:元素,元素個數,元素相對關系;元素操作:find,delete,insert,print,make null 簡單數組實現: 元素都被加上了有自然順序節點的鏈條,要預先估計一個較高的長度,有空間浪費。每

Java LinkNode簡單操作:初始化,遍歷,插入刪除

代碼 初始化 結構體 class 如果 traverse linknode eth com 由於java中沒有結構體,所以用一個類來定義鏈表,代碼如下 主要包括一個data,還有一個指向後面一個節點的next 重寫了toString函數,返回你想要的數據 定義鏈表的類: p

詳述線性單鏈,靜態連結串列和迴圈連結串列

線性表:由零個或多個數據元素組成的有限序列。     關鍵點: 有限序列第一個元素有且僅有一個前驅結點,最後一個與元素有且僅有一個後繼結點,中間元素有一個前驅結點和一個後繼結點線性表

C語言中存儲類別又分為四類:自動auto靜態static寄存器的register和外部的extern

字符變量 修飾 例如 register ext 進行 適合 sta -- 除法運算中註意: 如果相除的兩個數都是整數的話,則結果也為整數,小數部分省略,如8/3 = 2;而兩數中有一個為小數,結果則為小數,如:9.0/2 = 4.500000。 取余運算中註意: 該運算只適

區塊開源實現hyperledger fabric架構詳解轉載

hyperledger fabric是區塊鏈中聯盟鏈的優秀實現,主要程式碼由IBM、Intel、各大銀行等貢獻,目前v1.1版的kafka共識方式可達到1000/s次的吞吐量。本文中我們依次討論:區塊鏈的共通特性、fabric核心概念、fabric的交易執行流程。本文來源於筆

c語言==字元陣列與字串,char的取值範圍1

求char型別陣列的strlen長度 昨天老師給了一道題目 #include <stdio.h> #include "string.h" int main() { int i; char a[1000]; fo

C語言為四維陣列申請動態記憶體空間的方法

嘗試了用堆疊的方式為四維陣列申請動態記憶體空間,並將申請記憶體的操作封裝成了子函式,方便在主程式中使用。希望對大家有用。程式碼如下: #include <stdio.h> #include <stdlib.h> float****

C語言為四維陣列申請動態記憶體空間的方法

嘗試了用結構體為四維陣列申請動態記憶體空間,希望對大家有用。程式碼如下: #include <stdio.h> #include <stdlib.h> typedef struct _a{ float *dat; }A;

C庫-----字串string與整型int浮點型float之間的轉換

#include <stdlib.h> 1.int/float to string/array: C語言提供了幾個標準庫函式,可以將任意型別(整型、長整型、浮點型等)的數字轉換為字串

JS實現新增和刪除TR行

經過在網上的查詢,終於弄好了JS新增和刪除TR的效果。 JS程式碼如下: 新增tr的JS程式碼 function addRemark(){ //table_name 是table的id var tr = document.getElementById("table