C++數據結構——表


C++數據結構——表


1.簡介

形如A1,A2,、、、、An是一個一般的表,我們說這個表的大小為n。而且我們將大小為0的表叫做空表。

2.基本結構

首先我們來講講表的兩種基本實現方式:順序結構和鏈式結構
順序結構:順序結構使用的是數組來實現各種數據結構,它的好處是能夠快速的找到對應的元素,缺點是數組要求我們提前給出表的大小(這是非常嚴重的局限,尤其是你根本不確定表的大小的時候)並且插入和刪除操作會消耗線性時間(在數組中進行插入和刪除,后面的元素都要跟着向后/向前挪動一位,不要小看這個消耗,在你插入刪除操作頻繁時,這樣的消耗是巨大的)。
鏈式結構:鏈式結構使用的是帶有指針的結構實現,由於指針可以不連續存儲,所以可以避免順序結構的插入刪除操作所花的線性開銷,缺點是不能夠直接通過下標查找(對比數組的查找),所以我們會專門寫一個查找函數。
由於順序結構可以直接使用數組實現且基本原理與鏈式結構相同,且缺點更為明顯所以我們一般不使用順序結構實現表,並且在本作者數據結構專欄中都會使用鏈式結構(除非順序結構實現有獨特之處)。

鏈表分為:單鏈表、雙向鏈表、單雙向循環鏈表等,它們的基本結構圖如下:

單鏈表

雙向鏈表

單向循環鏈表

在鏈表的創建過程中,我們基本都會創建一個頭結點,頭結點的作用是人為的給我們的鏈表找到入口,會給你接下來的操作帶來很大的便利,推薦使用頭結點。

3.頭插法與尾插法

頭插法

尾插法

上圖中的方法就是頭插法與尾插法的過程示例,步驟分別用編號表示
①:首先將待插入的結點連接到后結點
②:前結點連接到待插入結點
③:將原本前結點與后結點的連接刪除
我們可以發現兩種插入方式的步驟都是一樣的,有區別的是插入時的位置(頭插法一直在頭結點后插入,尾插法一直在表的末尾插入)和插入后結點編號的順序(頭插法是4321,尾插法是1234),在使用時我們需要注意需求選擇不同的插入方式,比如表中我們可以選擇尾插法,這樣我們在遍歷表時我們可以得到順序的編號。

4.表的基本操作

表的基本操作有增(Insert)、刪(Delete)、查(Find)、判空(isEmpty)、判斷末尾(isLast)

4.1鏈表的類型申明

typedef struct node* Node;
struct node{
	int Element;
	Node next;
};

4.2判空函數

//判斷鏈表是否為空
bool isEmpty(Node head){
	return head->next==NULL;//如果頭結點的下一個為空,證明為空鏈表
}

4.3判斷末尾函數

//判斷當前結點是否為末尾結點
bool isLast(Node L){
	return L->next==NULL;//如果當前結點的下一個為空,那么當前結點即為末尾結點
}

你突然發現,怎么判空函數和判斷末尾的函數是一樣的?它們的形式是一樣的,但是含義卻不一樣,判空函數傳進來的結點參數必須是頭結點,只有當頭結點的下一個結點為空的時候鏈表才是空的,而判斷末尾函數所傳進來的結點參數可以是鏈表中的任意一個結點,所以通常還需要遍歷結點。

4.4插入函數

//插入一個值為x的結點,插入到參數結點的后面
void Insert(int x,Node L){
	Node p=new node;
	p->Element=x;
	p->next=L->next;//圖中:步驟1
	L->next=p;//步驟2、3,將前結點連接到待插入結點,那么前結點與后結點的連接自然就斷了
}

頭插法和尾插法在傳參時結點參數應該為頭結點,尾插法傳入末尾結點

4.5查找函數

//查找值為x的前驅結點
Node find(int x,Node L){
	Node p;
	p=L;
	while(p->next!=NULL&&p->next->Element!=x){
		p=p->next;
	}
	return p;
}

思考:為什么我們要找值為X的前驅結點,而不是它本身

4.6刪除函數

想要刪除一個結點,只需要將它的前驅結點和后驅結點鏈接起來,然后刪除它本身就可以了

//刪除一個值為x的結點
void Delete(int x,Node L){
	if(isEmpty(L))//如果鏈表為空,則直接返回
		return ;
	Node p=new node;
	p=findx(x,L);//找到值為X的前驅結點
	if(!isLast(p)){//
        Node temp=new node;
		temp=p->next;//temp結點是結點2的一個復制品
		p->next=temp->next;//步驟①完成時,P與2結點、2與3結點之間的鏈接自然斷裂
		delete(temp);
	}
}

思考:我們為什么不直接用結點2找到結點3,而是用一個它的復制品

5.完整代碼

#include<iostream>
using namespace std;
typedef struct node* Node;
struct node{
	int Element;
	Node next;
};
bool isEmpty(Node head){
	return head->next==NULL;
}
bool isLast(Node L){
	return L->next==NULL;
}
Node findx(int x,Node L){
	Node p;
	p=L;
	while(p->next!=NULL&&p->next->Element!=x){
		p=p->next;
	}
	return p;
}
void insert(int x,Node L){
	Node p=new node;
	p->Element=x;
	p->next=L->next;
	L->next=p;
}
void Delete(int x,Node L){
	if(isEmpty(L))
		return ;
	Node p=new node;
	Node temp=new node;
	p=findx(x,L);
	if(!isLast(p)){
		temp=p->next;
		p->next=temp->next;
		delete(temp);
	}
}
void print(Node L){//輸出函數
	while(L->next!=NULL){
		cout<<L->next->Element<<" ";
		L=L->next;
	}
	cout<<endl;
}
int main(){
	Node head=new node;
	head->next=NULL;//一定要指向NULL,因為判空等函數以此作為條件,還有些含義自己可以琢磨一下
//	頭插法
//	for(int i=0;i<5;i++){
//		insert(i+1,head);
//	}

// 尾插法
	Node flag=new node;
	flag=head;//flag作為末尾結點傳入
	for(int i=0;i<5;i++){
		insert(i+1,flag);
		flag=flag->next;
	}
	
	print(head);
	insert(6,head);
	print(head);
	Delete(3,head);
	print(head);
	return 0;
}

循環和雙向鏈表基於上面的代碼,自己可以嘗試一下。

第一次寫博客,有什么不足的地方歡迎大家指出


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM