【百度知道系列】C++链表(单双都有)基础(不同的问题,都是这一类就放进来了)

20200411

这里多编辑一下,对双链表的相关功能发上来供参考和给自己做个笔记~

 

指针和链表我感觉应该是刚上大学学C语言时候第一个比较懵的内容吧,把程序语言和内存存储去对应,emmm,需要习惯。然后如果是正在学习的小伙伴,还是建议自己写写代码~以下内容仅供参考了。

链表在C或者C++中基本都是通过定义结构体进行一个节点的生成,然后通过结构体内一个对自身类型的引用,来实现对下一个节点的跟踪。常见的比如整数链表如:L->1->3->4->8->null,我用这样的方式进行表示和打印,其基本结构定义应该类似这个样子:

typedef struct Node {
	int value;
	Node* next;
}LinkList;

其中,value就是数值,其实里这个node里可以有更多的东西,想要什么要什么,比如常见的题目还有要定义student的,可以加上char* name,char[10] number等等各种内容,随意的,其中务必要保留的就是自身的一个指针。单链表是这样定义,双链表还需要再加一个指针pre来指向这个节点前面的元素。用图片的话经常这样表示

所以每一次我们增加一个节点,都需要开辟一次内存单元,告诉系统,我要多一个多大的空间(里面会有数据、指针等等,是一个整体),然后去定义节点间的来连接关系。

Node* CreateNode(int value)	//根据值创建一个节点
{
	Node* node = (Node*)malloc(sizeof(node));//创建新节点并开辟空间
	node->value = value;
	node->next = NULL;
	return node;
}

我们一个链表无论有没有头节点,那一定会有一个指针来指向第一个元素的,否则我们链表定义了也没意义,因为不知道头在哪儿,尤其是单链表,一定要注意链表开头的指针不能丢。后面添加元素就比较简单了,让第一个元素的next等于我们Create的Node就可以了,因为我这个函数返回的也是个指针,也就是地址值。

一个链表无非其实与数据库功能一样,有增、删、改、查等常规要实现的功能。对于链表,一定要时刻注意保持引用。

新增:上面已经介绍,这里多说一句插入。需要插入时候,如果只希望有一个指针p指到插入位置之前的元素时,一定要注意流程。比如新元素指针q,一定要先让q->next=p->next,然后才能将p->next指定为q,否则原来的p->next将失去引用。

删除:类似于上面的反向过程,如果要删除中间的元素,一定要有两个指针,一个指向p待删除的元素,一个q指向删除之前的元素。其中删除过程是插入的倒序,也就是先让p->next=q->next,再释放q的空间。

改/查:主要流程就是遍历,顺藤摸瓜,顺着指针往下找到合适的元素为准。主要就是通过循环。链表的末尾一般都是让指针指向NULL的,内存引用通常会定义为0的位置,如果有报错引用了0x00000000之类的,那就是你的指针已经在null你却要访问它的元素或者next之类的属性,那是不存在的。

如果表头指针L,遍历通常让Node* p=l开始,循环条件是p!=NULL,每一次循环之后,使p=p->next来访问下一个元素。期间可以执行相应的操作。

 

以下我就把之前回答两个问题的代码都放上来,大部分功能应该都有了,大家需要的自取即可。

/*
Program:VRJerry
Date:2020/4/7
*/

#include "pch.h"
#include <iostream>
#include <stdio.h>


typedef struct Node {
	int value;
	Node* next;
}LinkList;

Node* CreateNode(int value)	//根据值创建一个节点
{
	Node* node = (Node*)malloc(sizeof(node));//创建新节点并开辟空间
	node->value = value;
	node->next = NULL;
	return node;
}

void SortInsert(LinkList* &list, int value)	//这里按照value的大小自小到达进行插入
{
	if (list == NULL)//如果一开始链表就是空的,那么直接定义一个新的结点,将它指定为头节点
	{
		list = CreateNode(value);
		return;
	}
	if (list->value > value)//一开始就比值大,则应该插入到开始
	{
		Node* tmp = list->next;
		list->next = CreateNode(value);
		list->next->next = tmp;
		return;
	}
	Node* p = list;
	while (p != NULL)
	{
		if (p->value <= value && (p->next == NULL || p->next->value >= value))
		{
			Node* tmp = p->next;
			p->next = CreateNode(value);
			p->next->next = tmp;
			return;
		}
		else
		{
			p = p->next;
		}
	}
}

void PrintList(LinkList* list)
{
	printf("当前链表情况:head->");
	while (list != NULL)
	{
		printf("%d->", list->value);
		list = list->next;
	}
	printf("NULL\n-------------------\n");
}
/*
Program:VRJerry
Date:2020/4/7
*/

#include "pch.h"
#include <iostream>
#include <stdio.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE - 1
#define OVERFLOW - 2

typedef int Status;
typedef char ElemType;

typedef struct Lnode {
	ElemType data;
	struct Lnode* next;
}Lnode, *Linklist;

Status Init_linklist(Linklist &L)
{
	L = (Linklist)malloc(sizeof(Lnode));
	L->next = NULL;
	return OK;
}

Status Find(Linklist list, int index, ElemType &element)
{
	Lnode* p = list->next;

	if (index <= 0)
		return INFEASIBLE;

	for (int i = 1; p != NULL; i++)
	{
		if (i == index)
		{
			element = p->data;
			return OK;
		}
		else
			p = p->next;
	}

	return OVERFLOW;
}

Status InsertSpace(Linklist list, int index)
{
	if (list == NULL)
		return OVERFLOW;
	if (index <= 0)
		return ERROR;

	Lnode* p = list->next;

	int i;
	Lnode* add = (Lnode*)malloc(sizeof(Lnode));
	(*add).data = ' ';

	if (index == 1)
	{
		list->next = add;
		add->next = p;
		return OK;
	}
	else
		for (i = 1; p != NULL; i++)
		{
			if (i + 1 == index)
			{
				(*add).next = p->next;
				p->next = add;
				return OK;
			}
			p = p->next;
		}
	return OVERFLOW;
}

Status Input(Linklist list, ElemType element)
{
	Lnode* p = list->next;
	Lnode* add = (Lnode*)malloc(sizeof(Lnode));
	(*add).data = element;
	(*add).next = NULL;

	if (p == NULL)
	{
		list->next = add;
	}
	else
	{
		while (p->next != NULL)
		{
			p = p->next;
		}
		p->next = add;
	}

	return OK;
}

Status PrintList(Linklist list)
{
	printf("list=");
	Lnode* p = list->next;
	while (p != NULL)
	{
		printf("%c->", p->data);
		p = p->next;
	}
	printf("NULL\n");

	return OK;
}

int main()
{
	Linklist linkList;
	ElemType e;
	Status stat;

	Init_linklist(linkList);

	stat = Input(linkList, 'a');
	stat = Input(linkList, 'b');
	stat = Input(linkList, 'c');

	PrintList(linkList);

	stat = InsertSpace(linkList, 4);

	stat = Find(linkList, -1, e);
	if (stat == OK)
	{
		printf("第-1位的元素:%c\n", e);
	}
	else
	{
		printf("寻找第-1位元素发生错误:%d\n", stat);
	}
	stat = Find(linkList, 3, e);
	printf("第3位的元素:%c\n", e);

	printf("最终结果:");
	PrintList(linkList);
	getchar();
}

 

 

       单链表是只有从前到后的指针,也就是不可能逆向去遍历,但是如果我们在当前节点中再加一个往前面一个节点的引用,就构成了一些可以双向引用的链表,也就是双链表了。比如下面这样

typedef struct dLinkNode
{
	dLinkNode* pre;
	dLinkNode* next;
	int x;
	int y;
}Point, *List;

那么,对于增加、插入、删除,就要同时注意前向和后项的引用,不要让链表丢失连接。几个小功能仅放上来,供大家查看吧


void PrintList(List l)
{
	if (l == NULL)
	{
		cout << "NULL" << endl;
		return;
	}
	Point* p = l;
	if (p != NULL)
		cout << "(" << p->x << "," << p->y << ")";
	while (p->next != NULL) 
	{
		cout << "->(" << p->x << "," << p->y << ")";
		p = p->next;
	}
	cout << "->(" << p->x << "," << p->y << ")" << endl;
}

Point* CreatePoint(int _x, int _y, Point* _pre = NULL, Point* _next = NULL)
{
	Point* p = (Point *)malloc(sizeof(Point));
	p->next = _next;
	p->pre = _pre;
	p->x = _x;
	p->y = _y;
	return p;
}

void AddPoint(List &l, int _x, int _y)
{
	Point* p = l;
	if (p == NULL)
	{
		p = CreatePoint(_x, _y);
		l = p;
		return;
	}
	while (p->next != NULL)
	{
		p = p->next;
	}
	p->next = CreatePoint(_x, _y, p);
}

void InsertPoint(List &l, Point* position, int _x, int _y)
{
	if (position == NULL||position->next==NULL)
		AddPoint(l, _x, _y);
	Point* q = position->next;
	position->next = CreatePoint(_x, _y, position, q);
	q->pre = position->next;
}

void DeletePoint(Point* p)
{
	if (p == NULL)
		return;
	Point* q = p->pre;
	q->next = p->next;
	q->next->pre = q;
	free(p);
}

void MoveToNext(Point* p)
{
	if (p == NULL || p->next == NULL)
		return;
	Point *q = p->next;
	Point *qn = q->next, *pp = p->pre;
	pp->next = q;
	q->pre = pp;
	q->next = p;
	p->pre = q;
	p->next = qn;
	qn->pre = p;
	/*p->pre->next = q;
	p->next = q->next;
	p->next->pre = p;
	q->pre = p->pre;
	p->pre = q;
	q->next = p;*/
}

void ExchangePoints(Point* p1, Point* p2)
{
	if (p1 == NULL || p2 == NULL)
		return;
	Point *p1p = p1->pre, *p1n = p1->next;
	Point *p2p = p2->pre, *p2n = p2->next;
	
	if(p1p!=NULL)
		p1p->next = p2;
	
	p2->pre = p1p;
	p2->next = p1n;
	
	if(p1n!=NULL)
		p1n->pre = p2;

	if(p2p!=NULL)
		p2p->next = p1;
	
	p1->pre = p2p;
	p1->next = p2n;

	if(p2n!=NULL)
		p2n->pre = p2p;

}

double PointDistance(Point p)
{
	return p.x*p.x + p.y*p.y;
}

bool IsPointLarger(Point p1, Point p2)
{
	int d1 = PointDistance(p1);
	int d2 = PointDistance(p2);
	
	if (d1 != d2)
		return d1 - d2 > 0;
	
	if (p1.x != p2.x)
		return p1.x - p2.x > 0;

	return p1.y - p2.y > 0;
}

//冒泡法
void listSort(List &l, bool isAscending)
{
	if (l == NULL || l->next == NULL)
		return;
	Point *p = l;
	int n = 0;
	while (p->next != NULL)
	{
		n++;
		p = p->next;
	}
	p = l;
	while (n != 0)
	{
		for (int i = 0; i < n ; i++)
		{
			if (isAscending)
			{
				if (IsPointLarger(*p, *(p->next)))
				{
					MoveToNext(p);
					if (p == l)
						l = l->pre;
					continue;
				}
			}
			else
			{
				if (!IsPointLarger(*p, *(p->next)))
				{
					MoveToNext(p);
					if (p == l)
						l = l->pre;
					continue;
				}
			}
			p = p->next;
		}
		n--;
		p = l;
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值