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