title: 链表的建立
date: 2019-02-27 08:49:25
tags: 数据结构
【动态链表】
1.创建链表
动态链表使用new delete需要添加头文件stdlib.h同时我们需要注意的是这里配合使用了指向前驱结点的指针pre和指向当前结点的p。通过数据域与指针域进行创建新结点。需要注意的是头结点head的数据域是不存储数据的。以下是基本的动态链表的代码:
#include<stdio.h>
#include<stdlib.h>
struct node { //链表结点
int data;
node* next;
};
//创建链表
node* create(int Array[]) {
node *p, *pre, *head; //pre保存当前结点的前驱结点,head为头结点
head = new node; //创建头结点
head -> next = NULL; //头结点不需要数据域,指针域初始为null
pre = head; //记录pre为head
for(int i = 0; i < 5; i++) {
p = new node; //新建结点
//将Array[i]赋值给新建的结点作为数据域 也可以从scanf输入
p->data = Array[i];
p->next = NULL; //新建结点的指针域为NULL
pre->next = p; //前驱结点的指针域设为当前新建结点的地址
pre = p; //把pre设为p,作为下一个结点的前驱结点
}
return head; //返回头结点指针
}
int main() {
int Array[5] = {5, 3, 6, 1, 2};
node* L = create(Array); //新建链表,返回的头指针head赋值给L
L = L->next; //从第一个结点开始有数据域
while(L != NULL) {
printf("%d", L->data);
L = L->next;
}
return 0;
}
输出结果:
53612
2.查找元素
已经有一个链表,如何查找其中是否有给定的元素。要从第一个结点开始直到查找到数字就计数。
int search(node* head, int x) { //统计次数
int count = 0; //计数器
node* p = head->next; //从第一个结点开始查找
while(p != NULL) { //只要没有到达链表的结尾
if(p->data == x) {
count++;
}
p = p->next;
}
return count;
}
3.插入元素
插入元素要注意的是一定是插入的元素先输入数据指向前驱结点的下一结点后再进行前驱结点指向新插入的结点,不可以颠倒顺序否则会丢失链表段。
void insert(node* head, int pos, int x) { //pos为插入节点的位置 x为插入的数据
node* p = head;
for(int i = 0; i < pos - 1; i++) {
p = p->next; //pos-1是为了使得pre到达插入节点的前一个结点
}
node* q = new node; //新建结点
q->data = x; //新建结点的数据域为x
q->next = p->next; //新建结点的下一个结点为p的下一个结点
p->next = q; //将前一个结点指向新结点
}
4.删除结点
删除元素是删除链表上所有值为给定的x,例如链表为53612我需要删除6就使得链表变为5312.
删除操作是这样的进行的:
void del(node* head, int x) {
node* p = head->next; //p从第一个结点开始枚举
node* pre = head; //pre始终保存的是p的前一个结点
while(p != NULL) {
if(p->data == x) {
pre->next = p->next;
delete(p);
p = pre->next;
} else {
pre = p;
p = p->next;
}
}
}
以上的代码组合起来栗子如下:
#include<stdio.h>
#include<stdlib.h>
struct node { //链表结点
int data;
node* next;
};
//创建链表
node* create(int Array[]) {
node *p, *pre, *head; //pre保存当前结点的前驱结点,head为头结点
head = new node; //创建头结点
head -> next = NULL; //头结点不需要数据域,指针域初始为null
pre = head; //记录pre为head
for(int i = 0; i < 5; i++) {
p = new node; //新建结点
//将Array[i]赋值给新建的结点作为数据域 也可以从scanf输入
p->data = Array[i];
p->next = NULL; //新建结点的指针域为NULL
pre->next = p; //前驱结点的指针域设为当前新建结点的地址
pre = p; //把pre设为p,作为下一个结点的前驱结点
}
return head; //返回头结点指针
}
int search(node* head, int x) { //统计次数
int count = 0; //计数器
node* p = head->next; //从第一个结点开始查找
while(p != NULL) { //只要没有到达链表的结尾
if(p->data == x) {
count++;
}
p = p->next;
}
return count;
}
void insert(node* head, int pos, int x) { //pos为插入节点的位置 x为插入的数据
node* p = head;
for(int i = 0; i < pos - 1; i++) {
p = p->next; //pos-1是为了使得pre到达插入节点的前一个结点
}
node* q = new node; //新建结点
q->data = x; //新建结点的数据域为x
q->next = p->next; //新建结点的下一个结点为p的下一个结点
p->next = q; //将前一个结点指向新结点
}
void del(node* head, int x) {
node* p = head->next; //p从第一个结点开始枚举
node* pre = head; //pre始终保存的是p的前一个结点
while(p != NULL) {
if(p->data == x) {
pre->next = p->next;
delete(p);
p = pre->next;
} else {
pre = p;
p = p->next;
}
}
}
int main() {
int Array[5] = {5, 3, 6, 1, 2};
//创建动态链表
node* L = create(Array); //新建链表,返回的头指针head赋值给L
node* head;
head = L;
L = L->next; //从第一个结点开始有数据域
while(L != NULL) {
printf("%d", L->data);
L = L->next;
}
//查询操作
L = head;
printf("\n%d", search(L, 3));
//插入操作
L = head;
insert(L, 3, 1);
printf("\n");
L = head->next;
while(L != NULL) {
printf("%d", L->data);
L = L->next;
}
//删除操作
printf("\n");
L = head;
del(L, 1);
L = head->next;
while(L != NULL) {
printf("%d", L->data);
L = L->next;
}
return 0;
}
输出结果:
53612
1
531612
5362
【静态链表】
动态链表是需要指针建立结点与结点之间的联系。对于一些问题结点的地址是比较小的整数的时候(比如5位数字的地址),就没有必要去建立动态链表,而应该使用方便很多的静态链表。
静态链表实现原理是hash,即通过建立一个结构体数组,并且令数组的下标直接表示为结点的地址,故静态链表是不需要头结点。定义方法:
struct Node {
typename data; //数据域
int next; //指针域
}node[size];
在此处的定义,next为一个int型的整数,用于存放下一结点的地址(事实上是数组的下标)。例如,如果初始结点的地址为11111,第二个结点的地址为22222,第三个结点的地址为33333,且第三个结点为链表的末尾,那么整个静态链表可以通过以下的方式连接起来:
node[11111] = 22222;
node[22222] = 33333;
noed[33333] = -1; //-1对应动态链表中的NULL,表示没有后继结点
静态链表中还需要注意一点,我们需要把结构体类型名称与结构体变量的名称设置为不同的名字(即Node和node),事实上在一般情况下他们是可以相同的,但是由于静态链表是由数组实现的,那么就有可能需要对其进行排序,这个时候如果结构体类型名和结构体变量名相同,sort函数就会报编译出错。因此在使用静态链表的时候,尽量不要把结构体的类型名和结构体变量名称取为同样的名字。