【線性表】單鏈表及其基本運算和應用

單鏈表的c語言定義
typedef struct Node {
	ElemType data;/*數據域*/
	struct Node *next;/*指針域*/
} Node,*Linklist;/*給node起兩個別名,這兩個別名等效*/
LinkLIst L;/*L爲單鏈表的頭指針,也稱爲單鏈表L*/

LinkList 與 Node*同爲結構指針類斜體樣式型,這兩種類型是等價的。

通常我們習慣上用LinkList說明指針變量,強調它是某個單鏈表的頭指針變量,用
Node*來定義指向單鏈表中節點的指針。

單鏈表的基本運算
一、求帶頭節點單鏈表的長度
int listlength(linklist L){
	node *p;
	p=->next;
	j=0;/*用來存放單鏈表的長度*/
	while(p!=NULL){
		p=p->next;
		j++;
	}
	return j;
} 
二、建表
1.建立空表
InitList(linklist *L)/*建立空表*/{
	L=(linklist*)malloc(sizeof(node));
	L->next=NULL;
} 
2.頭插法建表
linklist creatfromhead(linklist l){
	node *s;
	char c;
	int flag=1;/*設置一個標誌,初值爲1,當輸入“$”時,flag爲0,建表結束*/
	while(flag){
		c=getchar();
		if(c!='$'){
			s(node*)malloc(sizeof(node))
			/*申請新結點s*/
			s->data=c;
			s->next=L->next;
			/*將結點s頭插入鏈表L*/
			L->next=s; 
		}
		else flag=0;
	}
}
3.尾插法建表
linklist createfromtail(linklist L){
	linklist L;
	node *r,*s;
	char c;
	int flag=1;/*設置一個標誌,初值爲1,當輸入“$”時,flag爲0,建表結束*/
	r=L;/*r指針始終動態指向鏈表的當前表尾,以便做尾插入,其初值指向頭結點*/
	while(flag){
		c=getchar();
		if(c!='$'){
			s=(node*)malloc(sizeof(node));
			s->data=c;
			r->next=s;
			r=s;/*r就是當前尾結點*/
		} 
		else{
			flag=0;
			r->next=NULL;/*將最後一個結點的next鏈域置爲空,表示鏈表結束*/
		}
	}
} 
三、查找
1.按序號查找
node *get(linklist L,int i)
/*在帶頭結點的單鏈表L中查找第i個結點,
若找到(1<=i<=n),則返回該結點的存儲位置,否則返回NULL*/
{
	int j=0;/*計數器*/
	node *p;
	p=L;/*從頭結點開始掃描*/
	while((p->next!=NULL)&&(j<i)){
		p=p->next;/*掃描下一結點*/
		j++;/*已掃描結點計數器*/
	}
	if(i==j)return p;/*找到了第i個點*/
	else return NULL;/*找不到,i<=0或i>n*/	
} 
2.按值查找
node *locate(linklist l,elemtype key)
/*在帶頭結點的單鏈表L中查找其結點值等於key的結點,
若是找到則返回該結點的位置p,否則返回NULL*/
{
	node *p;
	p=l->next;/*從表中第一個結點比較*/
	while(p!=NULL){
		if(p->data!=key)
		p=p->next;
		else break;/*找到結點key退出循環*/
	} 
	return p; 
}
四、單鏈表插入
void inslist(linklist L,int i,elemtype e){
	node *pre,*s;
	int k=0;
	pre=L;
	while(pre!=NULL&&k<(i-1))
	/*在第i個元素之前插入,則先找到第i-1個數據元素的存儲位置
	使pre指針指向它*/
	{
		pre=pre->next;
		k++; 
	}
	if(!pre)/*如果當前位置pre爲空,表示已找完但還未數到第i個
	說明插入位置不合理*/
	{
		printf("插入位置不合理");
		return ERROR; 
	}
	s=(node*)malloc(sizeof(node));
	/*爲s申請一個新結點並由s指向它*/
	s->data=e;
	/*將待插入結點的值e賦給s的數據域*/
	s->next=pre->next;/*完成插入操作*/
	pre->next=s;
	return OK; 
} 
五、單鏈表刪除
void dellist(linklist L,int i,elemtype *e)
/*在帶頭結點的單鏈表L中刪除第i個元素,
並將刪除的元素保存到變量*e中。*/
{
	node *p,*r;
	int k=0;
	p=L;
	while(p->next!=NULL&&k<(i-1))
	/*尋找被刪除結點i的前驅結點i-1使p指向它*/
	{
		p=p->next;
		k++; 
	}
	if(k!=i-1)
	/*即循環是因爲p->next=NULL而跳出來的*/
	{
		printf("刪除位置i不合理");
		return error; 
	}
	r=p->next;
	p->next=p->next->next;
	*e=r->data;
	free(r);/*釋放被刪除結點所佔內存空間*/
} 
算法應用示例
求兩個集合的差
void difference(linklist la,linklist lb) {
	node *pre,*p,*q,*r;
	pre=la;
	p=la->next;
	while(p!=NULL) { /*逐個確定A表一個元素*/
		q=lb->next;/*查是否屬於b表*/
		while(q!=NULL&&q->data!=p->data) {
			q=q>next;
		}
		if(q!=NULL) {
			r=p;
			pre->next=p->next;
			p=p->next;
			free(r);
		} else {
			pre=p;
			p=p->next;
		}
	}
}
帶頭結點單鏈表就地逆置問題
【問題分析】逆置就是使得表中內容由原來的(a1,a2,…,ai-1,ai,ai+1, …,an)變爲 (an,an-1,…,ai+1,ai,ai-1, …,a1)。就地逆置就是不需要額外申請結點空間,只需要 利用原有的表中的節點空間。若對順序表中的元素進行逆置,可以藉助於“交換”前後相應 元素;對單鏈表中的元素進行逆置,則不能按“交換”思路,因爲對於鏈表中第 i 個結點需 要順鏈查找第 n-i+1(鏈表長度爲 n)個結點,逆置鏈表的時間複雜度將達 O(n2)。

【算法思路】用頭插法完成

  • 【初始化】逆置鏈表L初始爲空表,指針p指向原表當前處理結點
  • 【頭插法】依次取原鏈表中當前結點p
    將其作爲第一個結點插入到逆置鏈表L的表頭L
    q爲保存原鏈表當前結點的下一個處理位置

在這裏插入圖片描述
【算法描述】

void reverselist(linklist l)
//逆置帶頭結點的單鏈表L 
{
	p=l->next;//記錄原表第一個元素結點的地址 
	l->next=NULL;//從將頭結點的next域置空得新空鏈表
	while(p!=NULL){
		q=p->next;/*q 指針保留原鏈表當前處理結點的下一個結點*/
		p->next=l->next;
		l->next=p;/*p 指向下一個待插入的結點*/
		p=q;/*p 指向下一個待插入的結點*/
	}
}
二進制數加一運算

建立一個帶頭結點的線性鏈表,用以存放輸入的二進制數,鏈表中每個結點的
data 域存放一個二進制位。並在此鏈表上實現對二進制數加 1 的運算

【問題分析】
①建鏈表:帶二進制數可用帶頭結點的單鏈表存儲,第一個結點存儲二進制數的最高位,依次存儲,最後一個結點存儲二進制數的最低位。
②二進制加法規則:實現二進制數加 1 運算,方向從低位往高位找到第一個值爲 0 的位,把該位改成1,其後所有各位改成0
在這裏插入圖片描述在這裏插入圖片描述

③鏈表實現二進制加 1 時,從高位往低位與運算方向正好相反,從第一個結點開始找,找出最後一個值域爲 0 的結點,把該結點值域賦爲 1,其後所有結點的值域賦爲 0。

④若在鏈表中未找到值域爲 0 的結點,則表示該二進制數各位均爲 1,此時,申請一新結點,值域爲 1,插入到頭結點與原鏈表的第一個結點之間,成爲新鏈表的第一個結點,其後所有結點的值域賦爲 0。

【算法描述】

void binadd(linklist l) {
	node *q,*r,*s;
	q=l->next;
	r=l;
	while(q!=NULL)
	//找到最後一個值域爲0的點
	{
		if(q->data==0) r=q;
		q=q->nest;
	}
	if(r!=l) 
	//能夠找到值域爲0的點
	{
		r->data=1;/*將最後一個值域爲 0 的結點的值域賦爲 1*/
	} else //該二進制數各位均爲 1
	{ 
		s=(node*)malloc(sizeof(node));/*申請新結點存放最高進位*/
		s->data=1;/*值域賦爲 1*/
		s->next=l->nest;
		l->nest=s;/*插入到頭結點之後*/
		r=s;
	}
	r=r->nest;
	while(r!=NULL) 
	/*將後面的所有結點的值域賦爲 0*/
	{ 
		r->data=0;
		r=r->nest;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章