【数据结构】链表总结

链表总结

    • 指针实现链表
        • 单链表
        • 双链表
    • 结构数组模拟链表
        • 单链表
        • 双链表
    • 数组模拟链表的更简版本
        • 单链表
        • 双链表
    • vector模拟链表
        • vector直接模拟链表
        • 模拟vector实现链表
    • 对链表的封装--类实现
        • 单链表
        • 双链表
    • 对链表的泛化--泛型实现
        • 单链表
        • 双链表

指针实现链表

单链表
#include 

using namespace std;

typedef int TELemType;

const int N = 100010;

// 链表节点 
struct node{
	TELemType data;
	node* next;
}; 

//初始化 
node* init() 
{
	node* head = new node;
	head->next = NULL;
	return head;
}

// 查找值为x的结点的个数 
int search(node* head, int x)
{
	int count = 0;
	node* p = head->next;
	while(p){
		if(p->data == x) count ++;
		p = p->next;
	}
	return count;
}

// 在第k个结点后插入结点 
void insert(node* head, int k, int x)
{
	node* p = head;
	for(int i = 0; i < k; i ++)	p = p->next;
	node* q = new node;
	q->data = x;
	q->next = p->next;
	p->next = q;
} 

// 删除第k个结点后面的结点
void remove(node* head, int k)
{
	node* p = head;
	
	// 分删除头结点和删除其他结点两种情况
	if(k){
		p = head->next;
		head = p->next;
		delete(p);
	}
	else{
		for(int i = 0; i <= k; i ++)	p = p->next;
		node* q = p->next;
		p->next = q->next;
		delete(q);
	}
}

// 删除值为x的结点 
void del(node* head, int x)
{
	node* p = head->next;
	node* pre = head;
	while(p){
		if(p->data == x){
			pre->next = p->next;
			delete (p);
			p = pre->next;
		}
		else{
			pre = p;
			p = p->next;
		}
	}
} 
 
// 输出链表
void listprint(node* head)
{
	node* p = head->next;
	while(p){
		cout<<p->data<<' ';
		p = p->next;
	}
} 
双链表

结构数组模拟链表

单链表
#include 

using namespace std; 

const int N = 100010;

typedef int TELemType;

struct node{
	TELemType val; // 数据域
	int nex;       // 指针域
}Node[N];

int head, idx;
// head是链首指针
// idx是当前可以使用的数组元素的下标

// 初始化 
void init()
{
	head = -1;
	idx = 0;
}

/*
	注意区分链首指针和头结点 
	头结点是第1个结点,但是下标不确定
	链首指针初始值为-1,以后值为头结点下标 
*/ 

/*
	头结点一般放在第一个结点之前,数据域无意义
	头结点用来统一首元结点(第一个数据域有意义的结点)和其他结点的操作
	本模板的头结点不是常规意义的头结点,而是和首元结点是同一个结点
*/
// 插入头结点 
void head_insert(int x)
{
	Node[idx].val = x;
	Node[idx].nex = head;
	head = idx ++;
} 

// 在第k个结点后面插入结点 
void insert(int k, int x)
{
	// 注意数组下标从0开始,第k个结点下标是k-1
	k = k-1;
	Node[idx].val = x;
	
	Node[idx].nex = Node[k].nex; 
	Node[k].nex = idx ++;
}

// 删除第k个结点后面的结点
void remove(int k)
{
	// 分删除头结点和删除其他结点两种情况
	if(!k)	head = Node[head].nex;
	else	Node[k-1].nex = Node[node[k-1].nex].nex;
} 

// 删除值为x的结点(可能删除多个结点) 
void del(int x) 
{
	// 判断是否删除头结点 
	if(Node[head].val == x)	head = Node[head].nex;
	
	// 遍历头结点之后的结点 
	for(int i = head; i != -1; i = Node[i].nex){
		if(Node[i].nex != -1 && Node[Node[i].nex].val == x)	
			Node[i].nex = Node[Node[i].nex].nex;		
	} 
}

// 查找值为x的结点的个数 
int search(int x)
{
	int count = 0;
	for(int i = head; i != -1; i = Node[i].nex)
		if(Node[i].val == x)	count ++;
	return count;
} 

// 输出链表
void listprint()
{
	for(int i = head; i != -1; i = Node[i].nex)
		cout<<Node[i].val<<' ';
} 

双链表
#include 

using namespace std;

const int N = 100010;

typedef int TELemType;

struct node{
	TELemType val; // 数据域 
	int pred; // 前驱指针 
	int succ; // 后继指针 
}Node[N];

int idx; // idx是当前可以使用的数组元素的下标

// 初始化双链表(链首指针和链尾指针) 
void init()
{
	Node[1].pred = 0;
	Node[0].succ = 1;
	idx = 2;
} 

// 在第k个结点右侧插入结点
void insert(int k, int x)
{
	Node[idx].val = x;
	
	Node[idx].pred = k;
	Node[idx].succ = Node[k].succ;
	
	Node[node[k].succ].pred = idx;
	Node[k].succ = idx ++;
} 

// 删除第k个结点
void remove(int k) 
{
	Node[node[k].pred].succ = Node[k].succ;
	Node[node[k].succ].pred = Node[k].pred; 
}

数组模拟链表的更简版本

其实就是解开对结构数组的封装,这样写起来更简洁方便(但是略微难懂),比赛一般使用这种做法。
解开封装后数据域数组和指针域数组通过数组下标(相同)联系

单链表
/*
易错点:
	1.忘记初始化链表
	2.删除节点要分删除头节点和删除其他节点两种情况
	3.注意数组下标从0开始,第k个节点下标是k-1
*/

#include

using namespace std;

const int N = 100010;

int head, val[N], nex[N], idx;

// val数组存放节点值,nex数组存放当前节点的下一个节点的地址
// head是链首指针,idx是当前可以使用的数组元素的下标值
// 数据和指针通过数组下标联系起来

// 初始化
void init()
{
    head = -1;
    idx = 0;
}

// 插入头节点
void head_insert(int x)
{
    val[idx] = x;
    nex[idx] = head;
    head = idx ++;
}

//在第k个节点后面插入节点
void insert(int k, int x)
{
	// 注意数组下标从0开始,第k个节点下标是k-1
	k = k - 1
    val[idx] = x;
    
    nex[idx] = nex[k];
    nex[k] = idx ++;
}

//删除第k个节点后面的节点
void remove(int k)
{
	// 删除节点要分删除头节点和删除其他节点两种情况
    if(!k)  head = nex[head];
    else    nex[k-1] = nex[nex[k-1]];
}

// 删除值为x的结点(可能删除多个结点) 
void del(int x) 
{
	// 判断删除不删除头结点 
	if(val[head] == x)	head = nex[head];
	
	// 遍历头结点之后的结点 
	for(int i = head; i != -1; i = nex[i]){
		if(nex[i] != -1 && val[nex[i]] == x)
			nex[i] = nex[nex[i]];
	}
}

// 查找值为x的结点的个数 
int search(int x)
{
	int count = 0;
	for(int i = head; i != -1; i = nex[i])
		if(val[i] == x)	count ++;
	return count;
}

// 输出链表
void listprint()
{
	for(int i = head; i != -1; i = nex[i])
		cout<<val[i]<<' ';
}
双链表
/*
易错点:
	1.忘记初始化链表
	2.数组前两个元素分别被用作链首指针和链尾指针,所以第k个节点的下标是k+1
*/

#include 
#include 

using namespace std;

const int N = 100010;

int val[N], pred[N], succ[N], idx;
// val数组存放节点值,idx是当前可以使用的数组元素的下标值
// pred数组存放当前节点的前驱指针,succ数组存放当前节点的后继指针
// 数据和指针通过数组下标联系起来

// 初始化双链表
void init()
{
    pred[1] = 0;
    succ[0] = 1;
    idx = 2;
}

// 在第k个节点右侧插入节点
void insert(int k, int x)
{
    val[idx] = x;
    
    pred[idx] = k;
    succ[idx] = succ[k];
    
    pred[succ[k]] = idx;
    succ[k] = idx ++;
}

// 删除第k个节点
void remove(int k)
{
    succ[pred[k]] = succ[k];
    pred[succ[k]] = pred[k];
}

vector模拟链表

vector直接模拟链表

vector模拟单链表:

#include 

using namespace std;

typedef int TELemType;

//const int N = 100010;

// 链表结点 
struct node
{
	TELemType val1;
	TELemType val2;
	// 如val1表示(图)边终点,val2表示边权
};

vector<node> sinlist;
/*
 把sinlist换成数组即可实现邻接链表
 即:vector adjlist[N]
*/

//初始化
sinlist.clear();

// 在链表末插入结点
void tail_insert(int x, int k)
{
	sinlist.push_back(node(x, k)); 	// 调用结构体的构造函数
}

// 删除第pos个结点
void remove(int pos)
{
	sinlist.erase(sinlist.begin()+pos, sinlist.begin()+pos+1);
} 

vector模拟邻接链表

vecotr<typename> Arrayname[arraySize];

一维长度固定为arraySize,另一维变长,Arrayname[0]~Arrayname[arraySize-1]中的每一个都是一个vector容器

vector<vector<typename> >name

两个维度都是可变的

模拟vector实现链表

Python的list的实现方式正是数据结构vector(不是stl的vector)
Python list implementation

对链表的封装–类实现

单链表
#include 

using namespace std;

struct node{
	void* data;
	node* next;
}; 

class sinLink{
public:
	sinLink();
	~sinLink();
	void insert(void* x, int pos);
	void remove(int pos);
	int search(void* x);
	void listprint();
	void del(void* x);
	int getsize() const {return size;};
	node* getfront() {return head;};
private:
	node* head;
	int size;
};

// 构造函数 
sinLink::sinLink()
{
	head = new node;
	size = 0;
}

// 构析函数 
sinLink::~sinLink()
{
	if(head == NULL)	return;
	
	while(head)
	{
		node * pNext = head->next;
		delete head;
		head = pNext;
	}
	size = 0;
}

// 在pos位置后插入结点 
void sinLink::insert(void* x, int pos)
{
	node* p = head;
	for(int i = 0; i < pos; i ++)	p = p->next;
	node* q = new node;
	q->data = x;
	q->next = p->next;
	p->next = q;
	size ++;
}

// 删除pos位置后的结点 
void sinLink::remove(int pos)
{
	node* p = head;
	
	// 分删除头结点和删除其他结点两种情况
	if(pos){
		p = head->next;
		head = p->next;
		delete(p);
		size --;
	}
	else{
		for(int i = 0; i < pos; i ++)	p = p->next;
		node* q = p->next;
		p->next = q->next;
		delete(q);
		size --;
	}
} 

// 删除值为x的结点 
void sinLink::del(void* x)
{
	node* p = head->next;
	node* pre = head;
	while(p){
		if(p->data == x){
			pre->next = p->next;
			delete (p);
			size --;
			p = pre->next;
		}
		else{
			pre = p;
			p = p->next;
		}
	}
} 

// 查找值为x的结点的个数 
int sinLink::search(void* x)
{
	int count = 0;
	node* p = head->next;
	while(p){
		if(p->data == x) count ++;
		p = p->next;
	}
	return count;
}

// 输出链表
void sinLink::listprint()
{
	node* p = head->next;
	while(p){
		cout<<p->data<<' ';
		p = p->next;
	}
} 
双链表

对链表的泛化–泛型实现

单链表
#include 

using namespace std;

template <typename T> struct node{
	void* data;
	node* next;
}; 

template <typename T> class sinLink{
public:
	sinLink();
	~sinLink();
	void insert(void* x, int pos);
	void remove(int pos);
	int search(void* x);
	void listprint();
	void del(void* x);
	int getsize() const {return size;};
	node* getfront() {return head;};
private:
	node* head;
	int size;
};

// 构造函数 
template <typename T> sinLink::sinLink()
{
	head = new node;
	size = 0;
}

// 构析函数 
template <typename T> sinLink::~sinLink()
{
	if(head == NULL)	return;
	
	while(head)
	{
		node * pNext = head->next;
		delete head;
		head = pNext;
	}
	size = 0;
}

// 在pos位置后插入结点 
template <typename T> void sinLink::insert(void* x, int pos)
{
	node* p = head;
	for(int i = 0; i < pos; i ++)	p = p->next;
	node* q = new node;
	q->data = x;
	q->next = p->next;
	p->next = q;
	size ++;
}

// 删除pos位置后的结点 
template <typename T> void sinLink::remove(int pos)
{
	node* p = head;
	
	// 分删除头结点和删除其他结点两种情况
	if(pos){
		p = head->next;
		head = p->next;
		delete(p);
		size --;
	}
	else{
		for(int i = 0; i < pos; i ++)	p = p->next;
		node* q = p->next;
		p->next = q->next;
		delete(q);
		size --;
	}
} 

// 删除值为x的结点 
template <typename T> void sinLink::del(void* x)
{
	node* p = head->next;
	node* pre = head;
	while(p){
		if(p->data == x){
			pre->next = p->next;
			delete (p);
			size --;
			p = pre->next;
		}
		else{
			pre = p;
			p = p->next;
		}
	}
} 

// 查找值为x的结点的个数 
template <typename T> int sinLink::search(void* x)
{
	int count = 0;
	node* p = head->next;
	while(p){
		if(p->data == x) count ++;
		p = p->next;
	}
	return count;
}

// 输出链表
template <typename T> void sinLink::listprint()
{
	node* p = head->next;
	while(p){
		cout<<p->data<<' ';
		p = p->next;
	}
}
双链表

你可能感兴趣的:(【数据结构】链表总结)