c++数据结构—单向链表

7 篇文章 0 订阅

一、链表的原理

链表是线性表的链式存储方式,逻辑上相邻的数据在计算机内的存储位置不必须相邻,那么
怎么表示逻辑上的相邻关系呢?可以给每个元素附加一个指针域,指向下一个元素的存储位
置。如图所示:
在这里插入图片描述
从图中可以看出,每个结点包含两个域:数据域和指针域,指针域存储下一个结点的地址,
因此指针指向的类型也是结点类型

链表的核心要素:

每个节点由数据域和指针域组成
指针域指向下一个节点的内存地址

其结构体定义:

typedef struct _LinNoke
{
	int data;
	struct _LinNoke* next;

}LinkNode ,LinkList;

二、链表的算法实现

链表的节点均单向指向下一个节点,形成一条单向访问的数据链
在这里插入图片描述

单链表的初始化

typedef structLinkNode
{
int data;//结点的数据域
struct _LinkNode*next;//结点的指针域
} LinkNode,LinkList;//链表节点、链表

//构造一个空的单链表L
bool InitList (LinkList*& L)//构造一个空的单链表L
{
 L = new LinkNode;//生成新结点作为头结点,用头指针L指向头结点
 if( !L) return false;//生成结点失败
 L->next=NULL;//头结点的指针域置空
 return true;
}

前插法

bool ListInsert_front(LinkList*& L, LinkNode* node)
{
	if (!L || !node)return false;

	node->next = L->next;
	L->next = node;
	return true;
}

后插法

bool ListInsert_back(LinkList*& L, LinkNode* node)
{
	LinkNode* last = NULL;
	if (!L || !node)return false;
	last = L;

	while (last->next) last = last->next;

	node->next = NULL;
	last->next = node;
	return true;
}

指定位置插入

bool LinkInsert(LinkList*& L, int i, int& e)
{
	if (!L) return false;

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

	while (p && j < i - 1) //查找位置为i-1的结点,p指向该结点
	{
		p = p->next;
		j++;
	}

	if (!p || j > i - 1)
	{
		return false;

	}

	s = new LinkNode;//生成新的节点
	s->data = e;
	s->next = p->next;
	p->next = s;

	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;
	}
	cout << endl;

按值查找

bool Link_FindElem(LinkList* L, int e,int &index)
{
	//在带头结点的单链表L中查找值为e的元素
	LinkList* p;
	p = L->next;
	index = 1;

	if (!L || !L->next) 
	{
		index = 0;
		return false;
	}
		
	while (p&&p->data !=e)
	{
		p = p->next;
		index++;
	}

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


	return true;
}

单链表的删除

bool LinkDelte(LinkList*& L, int i)
{
	LinkList *p,*q;
	int index = 0;
	p = L;

	if (!L || !L->next)
	{
		return false;
	}

	while ((p->next)&&(index<i-1))
	{
		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;
	cout << "销毁链表" << endl;

	while (p)
	{
		L = L->next;  //L指向下一个链表
		cout << "删除元素" <<p->data<< endl;
		delete p;   //删除当前节点
		p = L;   //p移向下一个节点
	}

}

三、函数的调用

int main()
{
	LinkList* L = NULL;
	LinkNode* s = NULL;

	//1.初始化一个空的链表
	InitList(L);


	//2.使用前插法插入数据
	int n;

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

	while (n>0)
	{
		s = new LinkNode;
		cin >> s->data;
		ListInsert_front(L, s);
		n--;

	}


	//3.单链表的输出
	LinkPrint(L);*/


	//4.使用尾插法插入数据
	int n;

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

	while (n > 0)
	{
		s = new LinkNode;
		cin >> s->data;
		ListInsert_back(L, s);
		n--;

	}

	LinkPrint(L);

	//5.任意位置插入元素
	for (int j = 0; j < 3; j++)
	{
		int i, x; //i位置 x是值
		cout << "请输入插入的位置和元素:" << endl;
		cin >> i;
		cin >> x;

		if (LinkInsert(L, i, x))
		{
			cout << "插入成功.\n";
		}
		else
		{
			cout << "插入失败\n";
		}
		LinkPrint(L);

	}
	 
	//6.单链表根据位置获取元素
	int element = 0;
	if (Link_GetElem(L, 2, element))
	{
		cout << "获取第二个元素的值:" << element << endl;
	}
	else
	{
		cout << "获取失败" << endl;
	}

	//7.单链表根据值查询元素所在的位置
	int index = 0;

	if (Link_FindElem(L, 10, index))
	{
		cout << "查找元素10存在,所在位置:" <<index<< endl;
	}
	else
	{
		cout << "元素10不存在" << endl;
	}

	//8. 单链表删除元素
	if (LinkDelte(L, 2))
	{
		cout << "删除第二个元素" << endl;
		LinkPrint(L);
	}
	else
	{
		cout << "删除第二个元素失败" << endl;
	}


	//9.销毁单链表
	LinkDestroy(L);

	system("pause");
	return 0;
}

总结

由两部分组成:数据域和指针域,每个结点都有一个指针,每个节点指针的指向都是指向自身结点的下一个结点,最后一个结点的head指向为NULL,对单链表的操作只能从一端开始,如果需要查找链表中的某一个结点,则需要从头开始进行遍历。

与双向链表相比

  1. 其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。
  2. 单个结点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小,结点的访问方便,可以通过循环或者递归的方法访问到任意数据。

缺点:只能从头到尾遍历。只能找到后继,无法找到前驱,也就是只能前进。

双向链表

  1. 双向链表极高的灵活性,还表现在它可以封装成栈,队列。在没有随机访问的场景里,它几乎是完美的顺序结构。
  2. 每个节点有2个链接,一个是指向前一个节点(当此链接为第一个链接时,指向的是空值或空列表),另一个则指向后一个节点(当此链接为最后一个链接时,指向的是空值或空列表)。意思就是说双向链表有2个指针,一个是指向前一个节点的指针,另一个则指向后一个节点的指针。

优点:可以找到前驱和后继,可进可退;缺点:增加删除节点复杂

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双向链表是一种常见的数据结构,与单向链表相比,它每个节点都有两个指针,分别指向前驱节点和后继节点。这样,双向链表可以实现双向遍历,插入和删除操作也更加方便。 以下是用C语言实现双向链表的代码: ```c #include <stdio.h> #include <stdlib.h> // 双向链表节点结构体 typedef struct ListNode { int val; struct ListNode *prev; struct ListNode *next; } ListNode; // 创建双向链表节点 ListNode *createNode(int val) { ListNode *node = (ListNode *)malloc(sizeof(ListNode)); node->val = val; node->prev = NULL; node->next = NULL; return node; } // 插入节点到双向链表头部 ListNode *insertAtHead(ListNode *head, int val) { ListNode *node = createNode(val); if (head == NULL) { head = node; } else { node->next = head; head->prev = node; head = node; } return head; } // 插入节点到双向链表尾部 ListNode *insertAtTail(ListNode *head, int val) { ListNode *node = createNode(val); if (head == NULL) { head = node; } else { ListNode *cur = head; while (cur->next != NULL) { cur = cur->next; } cur->next = node; node->prev = cur; } return head; } // 删除双向链表中的节点 ListNode *deleteNode(ListNode *head, int val) { if (head == NULL) { return NULL; } ListNode *cur = head; while (cur != NULL && cur->val != val) { cur = cur->next; } if (cur == NULL) { return head; } if (cur == head) { head = head->next; if (head != NULL) { head->prev = NULL; } } else { cur->prev->next = cur->next; if (cur->next != NULL) { cur->next->prev = cur->prev; } } free(cur); return head; } // 打印双向链表 void printList(ListNode *head) { while (head != NULL) { printf("%d ", head->val); head = head->next; } printf("\n"); } // 主函数 int main() { ListNode *head = NULL; head = insertAtHead(head, 1); head = insertAtHead(head, 2); head = insertAtTail(head, 3); printList(head); // 2 1 3 head = deleteNode(head, 2); printList(head); // 1 3 head = deleteNode(head, 3); printList(head); // 1 head = deleteNode(head, 1); printList(head); // return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值