数据结构与算法 单链表

数据结构与算法 单链表

单链表

单链表是一种线性结构,单链表存储分成两部分,一部分存储数据,另一部分存储下一个节点(也就是指向下一个链表的地址(单指向))的地址。

1.定义链表,初始化链表

创建头节点,指针域置空。—代码注释为详细内容

//结构体定义链表
typedef struct _LinkNode {
    
    
	int data;   //数据域(存储数据)
	struct _LinkNode* next; //指针节点,指向(存储)下个链表节点的地址
}LinkNode,LinkList; 链表节点、链表

//初始化链表,定义头节点
bool InitList(LinkList* &L) {
    
     //构造一个空的单链表 L
	L = new LinkNode;   //创建新结点作为头结点,用头指针L指向头结点

	if (!L) {
    
    
		cout << "初始化链表失败!" << endl;
		return false;//生成结点失败
	}

	L->next = NULL; //头结点的指针域置空
	cout << "初始化链表成功!" << endl;
	return true;
}

2.单链表增加元素(前插法)

头节点后为每次插入的新节点,先插后出(最先插入的节点的节点元素,输出时则在最后面)

//前插法
bool ListInsert_front(LinkList*& L, LinkNode* node) {
    
    //L为头节点,node为新节点(子节点)
	if (!L || !node) return false;//防止链表为空

	node->next = L->next;//将头节点指向的下一个节点的地址赋值给新节点
	L->next = node; //将头节点指针指向新节点的地址
	return true;
}

3.尾插法

循环找出最后一个节点,然后在该位置插入,原最后节点指针指向新节点,新节点指针设置为空。

//尾插法
bool ListInsert_back(LinkList*& L, LinkNode* node) {
    
    
	LinkNode* last = NULL;

	if (!L || !node) return false;//判断是否为空

	last = L;//指向头链表,将头链表的地址赋给last指针

	//通过循环找到最后一个(节点)链表,即指针域存储为NULL的链表
	while (last->next) last = last->next;//如果链表中next指针不为空,那么就指向下一个链表的地址
	
	node->next = NULL;//将新节点的指针域设置为空
	last->next = node;//将原链表中最后一个节点的指针指向新链表的地址
	return true;
}

4.任意位置插入法

通过循环找出要插入位置的节点,然后将(要插入位置的)前节点指针指向新节点的地址,再将新节点指针指向(i+1)的节点的地址。

//任意位置插入
bool LinkInsert(LinkList*& L, int i, int& e) {
    
     //在单链表L中,在第i个位置插入元素e

	if (!L) return false; //判断是否为空

	int j = 0;
	LinkList* p, * s;

	p = L; //指针p指向头节点

	//找出要插入节点位置的前一个结点
	while (p && j < i - 1) {
    
    //查找位置为i-1的节点,p指向该节点
		p = p->next;
		j++;
	}

	if (!p || j > i - 1) {
    
    //判断p是否为空或者i值是否合法
		return false;
	}

	s = new LinkNode;//生成新节点
	s->data = e;//把插入的元素值赋值给新结点的数据域
	s->next = p->next;//将新节点指针指向原i节点的地址
	p->next = s;//将原(i-1)节点指针指向新节点地址

	return true;
}

5.获取单链表中的元素

通过要查找的位置i循环查找链表,找到后把元素值赋值给e。

//单链表的取值
bool Link_GetElem(LinkList* &L,int i,int &e) {
    
    
	//在带头结点的单链表L中查找第i个元素(i为查找的元素位置)
	//用e记录L中第i个数据元素的值(e为被查找的元素值)
	int index;
	LinkList* p;

	if (!L || !L->next) return false; //判断是否为空

	p = L->next;//p指向第一个节点
	index = 1;  //计数器,记录当前为哪一个节点(链表)

	while (p && index<i) {
    
    //链表依次向后扫描,直到指针p指向所指i个元素或者p为空
		p = p->next;     //p指向下一个节点(下一个链表的地址)
		index++;		//每循环一次index加1
	}

	if (!p || index > i) {
    
    
		return false;   //要查询的元素个数i不合法,i>n或i<=0
	}

	e = p->data;//将被查找节点的元素赋值给e
	return true;
}

6.单链表查找元素

循环判断该节点元素值是否与要查找元素值相等。

//单链表查找元素(查询)
bool Link_FindElem(LinkList* L, int e, int &index) {
    
    //按值查找
	//在带头结点的单链表L中查找值为e的元素
	LinkList* p;
	p = L->next; //指针p指向第一个节点
	index = 1; //计数器

	if (!L || !L->next) {
    
    
		index = -1;
		return false;
	}//判断是否为空

	while (p && p->data != e) {
    
     //判断该节点元素值是否与要查找元素值相等
		p = p->next;
		index++; //该节点位置
	}

	if (!p) {
    
    
		index = -1;
		return false;//查无此值
	}

	return true;
}

7.单链表中元素的删除(通过位置删除)

被删除节点要释放内存空间

//单链表中元素的删除
bool LinkDelete(LinkList*& L, int i) {
    
    //i为要删除节点的位置
	LinkList* p,*q;

	int index = 0;
	p = L;//将指针p指向头节点(链表)

	if (!L || !L->next) {
    
    
		return false;
	}//判断是否为空

	//判断p指针是否为空   要删除节点位置i是否合法
	while ((p->next) && (index < i - 1)) {
    
    //循环查找i节点
		p = p->next;
		index++;
	}

	if (!p->next || (index > i - 1)) {
    
    //当i>n或者i<1时,删除位置不合理
		return false;
	}

	q = p->next;		//临时保存被删除节点的地址以备释放空间
	p->next = q->next;	//将(被删除节点)的前节点的指针指向(被删除节点)的后节点的地址
	delete q;			//释放被删除节点的空间
	return true;
}

8.单链表的销毁

通过循环释放内存空间,完成销毁。

//单链表的销毁
void LinkDestroy(LinkList*& L) {
    
    
	//定义临时节点p指向头节点
	LinkList* p = L; //将指针p指向头节点(链表)
	cout << "销毁链表" << endl;

	while (p) {
    
    
		L = L->next;//L指向下一个节点
		delete p;   //删除当前节点
		p = L;		//p移向下一个节点
	}
}

9.完整代码

#include <iostream>
#include <string>
#include <stdlib.h>

using namespace std;

//结构体定义链表
typedef struct _LinkNode {
    
    
	int data;   //数据域(存储数据)
	struct _LinkNode* next; //指针节点,指向(存储)下个链表节点的地址
}LinkNode,LinkList; 链表节点、链表

//初始化链表,定义头节点
bool InitList(LinkList* &L) {
    
     //构造一个空的单链表 L
	L = new LinkNode;   //创建新结点作为头结点,用头指针L指向头结点

	if (!L) {
    
    
		cout << "初始化链表失败!" << endl;
		return false;//生成结点失败
	}

	L->next = NULL; //头结点的指针域置空
	cout << "初始化链表成功!" << endl;
	return true;
}

//前插法
bool ListInsert_front(LinkList*& L, LinkNode* node) {
    
    //L为头节点,node为新节点(子节点)
	if (!L || !node) return false;//防止链表为空

	node->next = L->next;//将头节点指向的下一个节点的地址赋值给新节点
	L->next = node; //将头节点指针指向新节点的地址
	return true;
}

//遍历链表
void LinkPrint(LinkList*& L) {
    
    
	LinkNode* p = NULL;

	if (!L) {
    
    
		cout << "链表为空." << endl;
		return;
	}

	p = L->next;

	while (p) {
    
    
		cout << p->data << "\t";
		p = p->next;
	}
	printf("\n");

}

//尾插法
bool ListInsert_back(LinkList*& L, LinkNode* node) {
    
    
	LinkNode* last = NULL;

	if (!L || !node) return false;//判断是否为空

	last = L;//指向头链表,将头链表的地址赋给last指针

	//通过循环找到最后一个(节点)链表,即指针域存储为NULL的链表
	while (last->next) last = last->next;//如果链表中next指针不为空,那么就指向下一个链表的地址
	
	node->next = NULL;//将新节点的指针域设置为空
	last->next = node;//将原链表中最后一个节点的指针指向新链表的地址
	return true;
}

//任意位置插入
bool LinkInsert(LinkList*& L, int i, int& e) {
    
     //在单链表L中,在第i个位置插入元素e

	if (!L) return false; //判断是否为空

	int j = 0;
	LinkList* p, * s;

	p = L; //指针p指向头节点

	//找出要插入节点位置的前一个结点
	while (p && j < i - 1) {
    
    //查找位置为i-1的节点,p指向该节点
		p = p->next;
		j++;
	}

	if (!p || j > i - 1) {
    
    //判断p是否为空或者i值是否合法
		return false;
	}

	s = new LinkNode;//生成新节点
	s->data = e;//把插入的元素值赋值给新结点的数据域
	s->next = p->next;//将新节点指针指向原i节点的地址
	p->next = s;//将原(i-1)节点指针指向新节点地址

	return true;
}

//单链表的取值
bool Link_GetElem(LinkList* &L,int i,int &e) {
    
    
	//在带头结点的单链表L中查找第i个元素(i为查找的元素位置)
	//用e记录L中第i个数据元素的值(e为被查找的元素值)
	int index;
	LinkList* p;

	if (!L || !L->next) return false; //判断是否为空

	p = L->next;//p指向第一个节点
	index = 1;  //计数器,记录当前为哪一个节点(链表)

	while (p && index<i) {
    
    //链表依次向后扫描,直到指针p指向所指i个元素或者p为空
		p = p->next;     //p指向下一个节点(下一个链表的地址)
		index++;		//每循环一次index加1
	}

	if (!p || index > i) {
    
    
		return false;   //要查询的元素个数i不合法,i>n或i<=0
	}

	e = p->data;//将被查找节点的元素赋值给e
	return true;
}

//单链表查找元素(查询)
bool Link_FindElem(LinkList* L, int e, int &index) {
    
    //按值查找
	//在带头结点的单链表L中查找值为e的元素
	LinkList* p;
	p = L->next; //指针p指向第一个节点
	index = 1; //计数器

	if (!L || !L->next) {
    
    
		index = -1;
		return false;
	}//判断是否为空

	while (p && p->data != e) {
    
     //判断该节点元素值是否与要查找元素值相等
		p = p->next;
		index++; //该节点位置
	}

	if (!p) {
    
    
		index = -1;
		return false;//查无此值
	}

	return true;
}

//单链表中元素的删除
bool LinkDelete(LinkList*& L, int i) {
    
    //i为要删除节点的位置
	LinkList* p,*q;

	int index = 0;
	p = L;//将指针p指向头节点(链表)

	if (!L || !L->next) {
    
    
		return false;
	}//判断是否为空

	//判断p指针是否为空   要删除节点位置i是否合法
	while ((p->next) && (index < i - 1)) {
    
    //循环查找i节点
		p = p->next;
		index++;
	}

	if (!p->next || (index > i - 1)) {
    
    //当i>n或者i<1时,删除位置不合理
		return false;
	}

	q = p->next;		//临时保存被删除节点的地址以备释放空间
	p->next = q->next;	//将(被删除节点)的前节点的指针指向(被删除节点)的后节点的地址
	delete q;			//释放被删除节点的空间
	return true;
}

//单链表的销毁
void LinkDestroy(LinkList*& L) {
    
    
	//定义临时节点p指向头节点
	LinkList* p = L; //将指针p指向头节点(链表)
	cout << "销毁链表" << endl;

	while (p) {
    
    
		L = L->next;//L指向下一个节点
		delete p;   //删除当前节点
		p = L;		//p移向下一个节点
	}
}


int main(void) {
    
    
	LinkList* L = NULL;  //定义一个链表指针,值置为空
	LinkList* s = NULL;
	//1.初始化链表
	InitList(L);
//-------------------------------------------------------------------------------
	//2.前插法
	int n;
	cout << "前插法创建单链表" << endl;
	cout << "请输入元素个数:";
	cin >> n;
	cout << "\n请依次输入n个元素:";

	while (n-- > 0) {
    
    
		s = new LinkNode;  //生成新节点

		cin >> s->data;
		ListInsert_front(L,s);
	}

	//打印链表
	LinkPrint(L);

	cout << "-------------------" << endl;
//-------------------------------------------------------------------------------

	//3.尾插法
	cout << "尾插法创建单链表" << endl;
	cout << "请输入元素个数:";
	cin >> n;
	cout << "\n请依次输入n个元素:";

	while (n > 0) {
    
    
		s = new LinkNode;  //生成新节点

		cin >> s->data;
		ListInsert_back(L, s);
		n--;
	}
	//打印链表
	LinkPrint(L);
//-------------------------------------------------------------------------------
	//4.任意位置插入元素
	int o;
	cout << "请问你要插几个元素:";
	cin >> o;
	for (int r = 0; r < o; r++) {
    
    
		int i, x;
		cout << "请输入插入的位置和元素(用空格隔开):";
		cin >> i;
		cin >> x;

		if (LinkInsert(L, i, x)) {
    
    
			cout << "插入成功!\n\n";
		}
		else {
    
    
			cout << "插入失败!\n\n";
		}
		//打印链表
		LinkPrint(L);
	}
//-------------------------------------------------------------------------------
	//5.获取链表中指定位置的元素值
	int value = 0;
	int i = 0;
	cout << "你要获取哪个位置的元素?" << endl;
	cin >> i;
	if (Link_GetElem(L, i, value)) {
    
    
		cout << "获取成功!  值为:" << value << endl;
	}
	else {
    
    
		cout << "获取失败!" << endl;
	}
//-------------------------------------------------------------------------------
	//6.查询链表中的元素
	int index = 0;
	int e;
	cout << "输入你要查询的元素值:";
	cin >> e;
	if (Link_FindElem(L, e, index)) {
    
    
		cout << "查询成功!  值为:" << e << endl;
		cout << "该值位置为" << index << endl;
	}
	else {
    
    
		cout << "查询失败!" << endl;
	}
//-------------------------------------------------------------------------------
	//7.单链表中元素的删除
	int w = 0;
	cout << "输入你要删除的元素位置:";
	cin >> w;
	if (LinkDelete(L, w)) {
    
    
		cout << "删除成功!" << endl;
	}
	else {
    
    
		cout << "删除失败!" << endl;
	}
	//打印链表
	LinkPrint(L);
//-------------------------------------------------------------------------------
	//8.销毁链表
	LinkDestroy(L);

	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45337964/article/details/102843981
今日推荐