线性表
- 定义:线性表是最基本的一种数据结构,是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
- 线性表中除了首元素和尾元素之外,每一个元素都有唯一的前驱和唯一的后续
- 线性表包括顺序表和链表,其中,可以将顺序表理解为数组
- 链表:链表由各结点组成,每个结点至少包括数据域和指针域。
在上图中的链表里,head 为头结点(一般不存放数据),5所在结点为尾结点且其指针域为NULL
物理与逻辑
- 物理上连续指的是数据元素在计算机内存中的地址是连续的
- 逻辑上连续指的是人们想象中的元素相邻
链表的定义
1、首先,定义一个节点
struct node//定义结点类型
{
int data;//数据域,存放数据
struct node *next;//指针域:该指针指向下一个node结点的地址,故其类型为struct node
};
2、结点类型定义完成之后需要定义一个结点变量并且给它申请空间
struct node *p;//定义结点变量p(指针)
p=new node;//动态申请空间(使指针指向一个地址)
链表的创建以及输出代码
#include <iostream>
#include <cstdio>
using namespace std;
struct node//定义链表结点类型
{
int data;//数据域,存放数据
struct node *next;//指针域:该指针指向下一个node结点的地址,故其类型为struct node
};
typedef struct node * Node;//struct node * = Node
void create(Node &head)
//创建函数
//不加&是复制了一个副本,creat函数运行完释放,加&是对同一片空间进行操作(知识点:值传递与引用)
{
Node r,p;
int x;
cin >> x;
if (head == NULL) head = new node;//如果当前head为空(头指针空),就为其申请一个结点空间;注意是node而不是Node
r = head;//head和r指针指向同一个结点
while (x != -1)//创建链表,以-1结束
{
p = new node;
p -> data = x;
p -> next = NULL;
r -> next = p;
r = p;
cin >> x;
}
}
void output(Node head)//输出链表
{
if (head == NULL)
{
cout << "the list is empty!" << endl;
return;
}
Node p = head -> next;
while (p != NULL)//p指针不为空
{
cout << p -> data << " ";//输出当前结点的数据域
p = p -> next;//指针后移
}
}
int main()
{
Node head = NULL;//head为头指针,注意要赋值为NULL,避免产生野指针,或者将creat函数中的head = new node写在这里
create(head);//输入:2 3 4 -1
output(head);//输出:2 3 4
return 0;
}
查找单链表中的某个元素x
bool find(Node head,int x)//查找单链表中是否含有x
{
Node p = head -> next;
while (p != NULL)
{
if (p -> data == x) return true;//找到x
else p = p -> next;
}
return false;//表示未找到x
}
查找链表中的第i个元素并输出其数据域
void get(Node head,int i)
{
Node p = head -> next;
int j = 1;
while ((p != NULL) && (j < i))
{
p = p -> next;
j++;
}
if (p != NULL) cout << p -> data << endl;//找到结点
else cout << "第i个结点不存在" << endl;//找不到结点:如链表中有4个元素,则无法找到第5个结点
}
find和get的测试代码
#include <iostream>
#include <cstdio>
using namespace std;
struct node//定义链表结点类型
{
int data;//数据域
struct node *next;//指针域
};
typedef struct node * Node;//struct node * = Node
void create(Node &head)//创建函数
{
Node r,p;
int x;
cin >> x;
if (head == NULL) head = new node;
r = head;//head和r指针指向同一个结点
while (x != -1)//创建链表,以-1结束
{
p = new node;
p -> data = x;
p -> next = NULL;
r -> next = p;
r = p;
cin >> x;
}
}
void output(Node head)//输出链表
{
if (head == NULL)
{
cout << "the list is empty!" << endl;
return;
}
Node p = head -> next;
while (p != NULL)//p指针不为空
{
cout << p -> data << " ";
p = p -> next;
}
}
bool find(Node head,int x)//查找单链表中是否含有x
{
Node p = head -> next;
while (p != NULL)
{
if (p -> data == x) return true;//找到x
else p = p -> next;
}
return false;//表示未找到x
}
void get(Node head,int i)//寻找链表中的第i个结点并输出其数据域
{
Node p = head -> next;
int j = 1;
while ((p != NULL) && (j < i))
{
p = p -> next;
j++;
}
if (p != NULL) cout << p -> data << endl;//找到结点
else cout << "第i个结点不存在" << endl;//找不到结点:如链表中有4个元素,则无法找到第5个结点
}
int main()
{
Node head = NULL;//赋值为NULL,避免产生野指针
create(head);
output(head);
cout << endl;
if(find(head,3)) cout << "Yes!" << endl;
get(head,4);
return 0;
}
链表的插入操作
在给定位置插入一个新结点
① s->next = p->next;
② p->next=s;
注:①②两句代码不可交换顺序,否则会发生断链。如下图,将结点4插入到结点3和结点5之间,如果先执行p->next=s;
则结点3指向结点5的指针会断开,从而找不到结点5,无法完成插入操作。
void insert(Node &head,int i,int x)//在第i个位置插入元素x
{
Node s = new node;//新建一个结点,用指针s指向
s -> data = x;
if (i == 1)//在第一个位置插入元素时需要特判(请尝试不写该句会怎么样)
{
Node p = head;
s -> next = p -> next;//插入
p -> next = s;
}
else
{
Node p = get(head,i - 1);//在第二个位置插入结点,需要先找到第一个结点的位置
s -> next = p -> next;//插入
p -> next = s;
}
}
链表的删除操作
p -> next = p -> next -> next;
void delNode(Node &head,int i)//删除第i个位置的结点(注意&符号)
{
if (i == 1)//此处要特判
{
Node p = head;
p -> next = p -> next -> next;//删除操作
}
else
{
Node p = get(head,i - 1);//删除第i个位置的结点,需要先找到第i - 1个结点的位置(直接调用get函数更简单)
p -> next = p -> next -> next;
}
}
插入和删除的测试代码
#include <iostream>
#include <cstdio>
using namespace std;
struct node//定义链表结点类型
{
int data;//数据域
struct node *next;//指针域
};
typedef struct node * Node;//struct node * = Node
void create(Node &head)//创建函数
{
Node r,p;
int x;
cin >> x;
if (head == NULL) head = new node;
r = head;//head和r指针指向同一个结点
while (x != -1)//创建链表,以-1结束
{
p = new node;
p -> data = x;
p -> next = NULL;
r -> next = p;
r = p;
cin >> x;
}
}
void output(Node head)//输出链表
{
if (head == NULL)
{
cout << "the list is empty!" << endl;
return;
}
Node p = head -> next;
while (p != NULL)//p指针不为空
{
cout << p -> data << " ";
p = p -> next;
}
}
Node get(Node head,int i)//寻找链表中的第i个结点,返回值为该结点的位置
{
Node p = head -> next;
int j = 1;
while ((p != NULL) && (j < i))
{
p = p -> next;
j++;
}
if (p != NULL) return p;
else return NULL;
}
void insert(Node &head,int i,int x)//在第i个位置插入元素x
{
Node s = new node;//新建一个结点,用指针s指向
s -> data = x;
if (i == 1)//在第一个位置插入元素时需要特判(请尝试不写该句会怎么样)
{
Node p = head;
s -> next = p -> next;//插入
p -> next = s;
}
else
{
Node p = get(head,i - 1);//在第二个位置插入结点,需要先找到第一个结点的位置
s -> next = p -> next;//插入
p -> next = s;
}
}
void delNode(Node &head,int i)//删除第i个位置的结点(注意&符号)
{
if (i == 1)//(请各位试一下如果此处不特判,会怎么样)
{
Node p = head;
p -> next = p -> next -> next;//删除操作
}
else
{
Node p = get(head,i - 1);//删除第i个位置的结点,需要先找到第i - 1个结点的位置(直接调用get函数更简单)
p -> next = p -> next -> next;
}
}
int main()
{
Node head = NULL;
create(head);//1 3 4
output(head);//1 3 4
cout << endl;
insert(head,1,2);//测试插入操作
output(head);//2 1 3 4
cout << endl;
delNode(head,4);//测试删除操作
output(head);//2 1 3
return 0;
}
求链表的实际长度(不包含头结点)
void len(Node head)
{
int length = 0;
Node p = head -> next;
while (p != NULL)
{
length++;
p = p -> next;
}
cout << length;
}
链表长度的测试代码
#include <iostream>
#include <cstdio>
using namespace std;
struct node//定义链表结点类型
{
int data;//数据域
struct node *next;//指针域
};
typedef struct node * Node;//struct node * = Node
void create(Node &head)//创建函数
{
Node r,p;
int x;
cin >> x;
if (head == NULL) head = new node;
r = head;//head和r指针指向同一个结点
while (x != -1)//创建链表,以-1结束
{
p = new node;
p -> data = x;
p -> next = NULL;
r -> next = p;
r = p;
cin >> x;
}
}
void output(Node head)//输出链表
{
if (head == NULL)
{
cout << "the list is empty!" << endl;
return;
}
Node p = head -> next;
while (p != NULL)//p指针不为空
{
cout << p -> data << " ";
p = p -> next;
}
}
Node get(Node head,int i)//寻找链表中的第i个结点,返回值为该结点的位置
{
Node p = head -> next;
int j = 1;
while ((p != NULL) && (j < i))
{
p = p -> next;
j++;
}
if (p != NULL) return p;
else return NULL;
}
void insert(Node &head,int i,int x)//在第i个位置插入元素x
{
Node s = new node;//新建一个结点,用指针s指向
s -> data = x;
if (i == 1)//在第一个位置插入元素时需要特判(请尝试不写该句会怎么样)
{
Node p = head;
s -> next = p -> next;//插入
p -> next = s;
}
else
{
Node p = get(head,i - 1);//在第二个位置插入结点,需要先找到第一个结点的位置
s -> next = p -> next;//插入
p -> next = s;
}
}
void delNode(Node &head,int i)//删除第i个位置的结点(注意&符号)
{
if (i == 1)//(请各位试一下如果此处不特判,会怎么样)
{
Node p = head;
p -> next = p -> next -> next;//删除操作
}
else
{
Node p = get(head,i - 1);//删除第i个位置的结点,需要先找到第i - 1个结点的位置(直接调用get函数更简单)
p -> next = p -> next -> next;
}
}
void len(Node head)
{
int length = 0;
Node p = head -> next;
while (p != NULL)
{
length++;
p = p -> next;
}
cout << length;
}
int main()
{
Node head = NULL;
create(head);//1 3 4
output(head);//1 3 4
cout << endl;
len(head);//3
cout << endl << endl;
insert(head,1,2);//测试插入操作
output(head);//2 1 3 4
cout << endl;
len(head);//4
cout << endl << endl;
delNode(head,4);//测试删除操作
output(head);//2 1 3
cout << endl;
len(head);//3
return 0;
}