线性表:单链表

1.单链表的存储

我们将这种只带有一个指针域的线性表称为单链表

链表中第一个结点的存储位置叫做头指针。

单链表的第一个结点钱附设一个结点,称为头结点

上一节我们提到过,线性表的最后一个元素是没有直接后继的,所以在链式存储中,我们将最后一个结点的指针域设置为null.

typedef struct LNode
{
	int data; //数据域
	struct LNode *next;//指针用
}LNode,*LinkList; //定义节点,以及头指针

这里直接定义的*LinkList类型是直接指向结构体的指针,这样如果用LinkList定义的时候比如说,LinkList L,L定义就是一个指针类型变量,如果要对结构体里面的东西进行操作的时候,对于指针类型要用L->date,L->next,必须要这样,但是如果要使用'.'运算符的话,必须要使用(*L).date、(*L).next,而此时*L可以直接当作一个变量来处理了。

2.建立链表

int creatlist(LinkList & L, int a[],int n)
{//逆位序输入数组a中的n个数,建立一个带有头结点的单链表。
	LinkList p;//定义一个指向Node结构体的指针
	int i;
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;   //先建立一个带有头结点的空链表
	L->data = n;      //头结点数据域存好元素个数
	for (i = n-1; i >=0; i--)  //逆序输入n个元素
	{
		p = (LinkList)malloc(sizeof(LNode));  //生成新结点
		p->data = a[i];  //赋值
		p->next = L->next;  //将头结点的指针指向刚申请的新结点
		L->next = p;     //将新申请结点的头指针把头结点连起来
	}
	return 0;
}

3.链表的查找

int search(LinkList &L, int i)
{
	LinkList q; //定义一个指向LNode结构体的指针
	q = L->next; //将头结点的指针指向q
	int j = 1;  
	while (j<i)
	{
		q = q->next;  //一直向下进行遍历,进行查找,对于原来的链表L是没有影响的
		j++;
	}
	return q->data;    //找到后返回找到的值

}

4.链表插入

void setin(LinkList L, int e, int i)
{
	LinkList p = L, q; //定义两个指向LNode结构体的指针,并且让p的指针指向L的头结点
	int j = 1;
	q = (LinkList)malloc(sizeof(LNode)); //申请一个结点
	while (p->next!=NULL&&j<i)   //进行遍历来查找插入点
	{
		p = p->next;
		j++;
	}
	q->data = e;   //赋值
	q->next = p->next;  //将原先指向p的下一个元素的指针赋给q,让q指向,完成了指针的传递
	p->next = q;   //这时候再让p的指针指向q,将整条链连贯起来
}

5.链表的删除

void Delete(LinkList &L, int i)
{
	int j = 1;
	LinkList p = L, q;  //定义两个指向LNode结构体的指针p,q,并且让p指向L的头结点
	while (p->next&&j<i)  //遍历找位置
	{
		p = p->next;
		j++;
	}
	q = p->next;        //此时的q为要删除的元素
	p->next = q->next;  //将删除元素指向下一个元素的指针赋值给它之前的元素,这样就直接把 
                        // 删除元素从链表中给断掉。
}

6.链表的元素值的修改

void change(LinkList L, int i, int e)
{
	LinkList p = L; //定义指向结构体的指针p,并且让p指针指向L的头结点
	p = p->next;    //让p指向第一个元素
	int j = 1;   
	while (j<i)//遍历查找
	{
		p = p->next;
		j++;

	}
	p->data = e;  //找到后赋值进行修改,应为在该地址上改的,因为地址对应是相等的所以L的值 
                  //也就修改了。
}

7.链表的就地逆置

就地逆置的思想:首先先把头结点和第一个元素连接断开,并且让头结点指向NULL,这样依次将第一、二、三...元素取出来,先插入第一个,让头结点指向一个元素,元素1指向NULL,再插入第二个元素,让头结点再指向第二个元素,第二个元素指向第一个元素....

void reverse(LinkList L)
{
	LinkList p, q; //定义指向结构体的指针p,q
	p = L->next;   //让p的指向第一个元素
	L->next = NULL;  //头结点指向NULL,为空
	while (p!=NULL)   
	{
		q = p;    //将q指向p的头指针
		p = p->next;   //p指针向下移动一个元素
		q->next = L->next;  //将原先L指向的元素让q指向
		L->next = q;        //让新结点头指针和L的头指针相连
	}


}

8.下面附上一个完全的代码:关于建立、查找、删除、更新、就地逆置、输出

#include <iostream>
#include <stdio.h>
using namespace std;
#pragma warning(disable:4996)
typedef struct LNode
{
	int data;
	struct LNode *next;
}LNode,*LinkList;
int creatlist(LinkList & L, int a[],int n)
{
	LinkList p;
	int i;
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	L->data = n;
	for (i = n-1; i >=0; i--)
	{
		p = (LinkList)malloc(sizeof(LNode));
		p->data = a[i];
		p->next = L->next;
		L->next = p;
	}
	return 0;
}
void putlist(LinkList  &L)
{
	LinkList p;
	p = L->next;
	while (p!=NULL)
	{
		printf("%d ", p->data);
		p = p->next;
	}
}
int search(LinkList &L, int i)
{
	LinkList q;
	q = L->next;
	int j = 1;
	while (j<i)
	{
		q = q->next;
		j++;
	}
	return q->data;

}
void Delete(LinkList &L, int i)
{
	int j = 1;
	LinkList p = L, q;
	while (p->next&&j<i)
	{
		p = p->next;
		j++;
	}
	q = p->next;
	p->next = q->next;
}
void setin(LinkList L, int e, int i)
{
	LinkList p = L, q;
	int j = 1;
	q = (LinkList)malloc(sizeof(LNode));
	while (p->next!=NULL&&j<i)
	{
		p = p->next;
		j++;
	}
	q->data = e;
	q->next = p->next;
	p->next = q;
}
void reverse(LinkList L)
{
	LinkList p, q;
	p = L->next;
	L->next = NULL;
	while (p!=NULL)
	{
		q = p;
		p = p->next;
		q->next = L->next;
		L->next = q;
	}


}
void change(LinkList L, int i, int e)
{
	LinkList p = L;
	p = p->next;
	int j = 1;
	while (j<i)
	{
		p = p->next;
		j++;

	}
	p->data = e;
}
int main()
{
	LinkList  L;
	int a[500];
	int n;
	int m;
	printf("\n请输入元素个数:");
	scanf("%d", &n);
	printf("\n请依次输入元素:");	
	for (int i = 0; i < n; i++)
		scanf("%d", &a[i]);
	creatlist(L,a,n);
	printf("\n输出链表中所有元素:");
	putlist(L);
	printf("\n请输入要查找的位置:");
	scanf("%d", &n);
	m=search(L,n);
	printf("\n第%d元素为%d",n,m);
	printf("\n请输入要删除的元素的位置:");
	scanf("%d", &n);
	Delete(L, n);
	printf("\n输出链表所有元素:");
	putlist(L);
	printf("\n请输入要插入的元素和其位置:");
	scanf("%d %d", &m, &n);
	setin(L,m,n);
	printf("\n输出链表所有元素:");
	putlist(L);
	printf("\n链表就地逆置输出:");
	reverse(L);
	putlist(L);
	printf("\n请输入修改的元素的位置和修改后的值:");
	scanf("%d %d", &n, &m);
	change(L, n, m);
	putlist(L);
	return 0;
}

下面转一篇写的关于存储结构的问题的博客:https://www.cnblogs.com/dangnianhefeng/p/5034260.html

下面一篇博客是关于结构体里的  '.'运算符和 '->'运算符的区别的:https://www.cnblogs.com/limeina/p/3665568.html

欢迎大家提出宝贵意见,感激不尽!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值