个人主页:Hello Code.
本文专栏:数据结构
如有问题,欢迎指正,一起学习~~
目录
概述
基本操作
初始化链表
创建
增
删
改
查
代码实现
C语言
Java
链表是一种在物理存储单元上非连续、非顺序的一种数据的存储结构。由一系列结点组成,结点可以在运行时动态生成。
链表主要可分为单链表、双链表、循环链表等。本文主要就做一下单链表的基本操作展示,其他的大家可以去自行研究。
单链表中每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
一般还会有head(头结点)、end(尾节点)以及p(临时指针)来帮助我们完成链表的一些基本操作
在上图中,N1称为头结点,N3为尾结点;N1是N2的前驱结点,N2是N1的后继结点
在对数据的操作中,最常见的就是增、删、改、查以及排序操作
本文会通过Java和C两种语言来对单链表进行代码展示
链表中每个结点对应的都是在内存中开辟的一处空间,它分为数据域和指针域两部分
c语言中使用malloc开辟,Java中则是通过new来开辟空间
在初始化的时候,就是开辟一处空间,将地址给head结点,因为初始化时没有其他结点,所以也需要将指针域赋值为NULL
在创建一个链表时,通过输入链表的结点个数,用for循环进行遍历,依次开辟各个空间并对每个结点的数据域和指针域赋值后,用指针将各个结点连接起来,就可以完成链表的创建工作,形成一个链表结构
在链表中增加元素,首先需要在内存中开辟一个空间作为新结点并赋值,找到需要添加的位置的前驱结点,让该结点断开原链接,指向被添加结点,再让被添加结点指向原后继结点即可完成。(若有头结点,则头插法和按位置插入类似;尾插法则不需要断开链接,直接让end指向新结点即可)
链表中元素的删除,首先需要遍历链表找到需要删除的结点的前驱结点,并让该结点直接指向被删结点的后继,就是通过跳过要删除的结点来实现删除操作。最后,在C语言中还应通过free()来释放掉被删除结点所开辟的内存空间,防止空间的浪费。
Java中不用free释放空间是因为Java具有垃圾回收机制,会在空闲时间自动处理
链表中结点的修改其实很简单,只需要通过遍历找到要修改的结点位置,然后直接给该结点赋上需要修改的值覆盖掉旧值即可
在遍历链表时,首先定义一个临时指针p指向head,然后通过不断地后移p指针(p=p->next),即可完成链表的遍历。查找各个结点在前几步操作中都有体现,这里就不做动图展示了,原理也不难,很容易理解
遍历指依次获取到每个结点,但并不是说遍历就是将数据都打印出来,获取到每个结点后可以进行各种操作,而不仅仅是打印。但在本文中,为了更直观的展示数据,遍历后的操作就定为打印
在代码实现部分,将通过C和Java两种语言进行,代码如下:
#include
#include
typedef int DataType;
typedef struct{
DataType data;
struct LinkList *next;
}LinkList;
LinkList *InitList(){
LinkList *head;
head = (LinkList*)malloc(sizeof(LinkList));
head->next = NULL;
return head;
}
void CreateList(LinkList *head, int n){
LinkList *end, *node;
DataType data;
int i;
end = head;
for(i = 0; i < n; i++){
node = (LinkList*)malloc(sizeof(LinkList));
printf("请输入结点数据:");
scanf("%d",&data);
node->data = data;
node->next = NULL;
end->next = node;
end = node;
}
printf("创建成功!\n");
}
void ListInsert(LinkList *head, int n){ // n表示需要添加的结点位置
LinkList *node, *p;
DataType data;
int m;
int length = ListLength(head);
p = head;
m = 0;
if(n <= (length + 1) && n >= 0){
while(p != NULL){
if(m == n - 1) break;
else{
p = p->next;
m++;
}
}
node = (LinkList*)malloc(sizeof(LinkList));
printf("请输入要插入结点的数据:");
scanf("%d",&data);
node->data = data;
node->next = p->next;
p->next = node;
printf("添加成功!\n");
}
else printf("插入位置错误,请重新输入!\n");
}
void ListDelete(LinkList *head,int n){
LinkList *q, *p;
int m = 0;
p = head;
while(m < n && p != NULL){
q = p;
p = p->next;
m++;
}
if(p != NULL){
q->next = p->next;
free(p);
printf("删除成功!\n");
}
else printf("该结点不存在,请重新输入!\n");
}
void ListChange(LinkList *head,int n){
LinkList *p;
DataType data;
int i = 0;
p = head;
while(i < n && p != NULL){
p = p->next;
i++;
}
if(p != NULL){
printf("请输入您要修改的值:");
scanf("%d",&data);
printf("%d已成功修改为%d\n",p->data,data);
p->data = data;
}else{
printf("结点不存在!\n");
}
}
void ListTraverse(LinkList *head){
LinkList *p = head->next;
printf("您存储的数据为:");
while(p != NULL){
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
main(){
LinkList *head;
int choice = 0;
int n;
head = NULL;
while(choice != 6){
printf("-----------链表的基本操作-----------\n");
printf(" 1.初始化 \n");
printf(" 2.增 \n");
printf(" 3.删 \n");
printf(" 4.改 \n");
printf(" 5.查 \n");
printf(" 6.退出 \n");
printf("------------------------------------\n");
printf("请输入你的选择:");
scanf("%d",&choice);
switch(choice){
case 1:
head = InitList();
printf("初始化成功!\n");
break;
case 2:
if(head == NULL) printf("未初始化,请初始化后再进行操作\n");
else{
printf("请输入您要增加的结点数量:");
scanf("%d",&n);
ListInsert(head,n);
}
break;
case 3:
if(head == NULL) printf("未初始化,请初始化后再进行操作\n");
else{
printf("请输入您要删除的结点:");
scanf("%d",&n);
ListDelete(head,n);
}
break;
case 4:
if(head == NULL) printf("未初始化,请初始化后再进行操作\n");
else{
printf("请输入您要修改的结点:");
scanf("%d",&n);
ListChange(head,n);
}
break;
case 5:
ListTraverse(head);
break;
case 6:
printf("退出成功,感谢您的使用!\n");
break;
}
}
}
private class Node{
public T data;
public Node next; // 指向下一个结点
public Node(T t){
this(t, null);
}
public Node(T t, Node next){
this.data = t;
this.next = next;
}
public void set(T t){
this.data = t;
}
}
public void addFirst(T t){ // 头插法
Node node = new Node(t);
node.next = this.head;
this.head = node;
this.size++;
}
public void add(T t, int index){ // 指定位置插入
if(index < 0 || index > this.size){
throw new IllegalArgumentException("index is error");
}
if(index == 0){
addFirst(t);
return;
}
Node preNode = this.head;
for(int i = 0; i < index - 1; i++){
preNode = preNode.next;
}
Node node = new Node(t);
node.next = preNode.next;
preNode.next = node;
this.size++;
}
public void addLast(T t){ // 尾插法
add(t, this.size);
}
public T remove(int index){ // 指定索引删除
if(index < 0 || index > this.size - 1){
throw new IllegalArgumentException("index is error");
}
T data = null;
if(index == 0){
data = head.data;
this.head = head.next;
this.size--;
return data;
}
Node preNode = this.head;
for(int i = 0; i < index - 1; i++){
preNode = preNode.next;
}
Node p = preNode.next;
data = p.data;
preNode.next = p.next;
this.size--;
return data;
}
public void remove(T t){ // 指定内容删除
int index = getIndex(t);
remove(index);
}
public T set(int index, T t){
Node p = this.head;
for(int i = 0; i < index; i++){
p = p.next;
}
T oldData = p.data;
p.set(t);
return oldData;
}
public boolean contains(T t){ // 查询该元素是否存在
Node p = this.head;
while(p != null){
if(p.data.equals(t)) return true;
p = p.next;
}
return false;
}
public int getIndex(T t){ // 查询指定元素对应索引
Node p = this.head;
for(int i = 0; i < this.size; i++){
T data = p.data;
if(data.equals(t)) return i;
else p = p.next;
}
return -1;
}
public void display(){
Node p = this.head;
while(p != null){
System.out.println(p.data);
p = p.next;
}
}
package LinkList;
public class LinkedList {
// 链表结点
private class Node{
public T data;
public Node next; // 指向下一个结点
public Node(T t){
this(t, null);
}
public Node(T t, Node next){
this.data = t;
this.next = next;
}
public void set(T t){
this.data = t;
}
}
private Node head; // 头结点
private int size; // 链表元素个数
public LinkedList(){
this.head = null;
this.size = 0;
}
// 增
public void addFirst(T t){
Node node = new Node(t);
node.next = this.head;
this.head = node;
this.size++;
}
public void add(T t, int index){
if(index < 0 || index > this.size){
throw new IllegalArgumentException("index is error");
}
if(index == 0){
addFirst(t);
return;
}
Node preNode = this.head;
for(int i = 0; i < index - 1; i++){
preNode = preNode.next;
}
Node node = new Node(t);
node.next = preNode.next;
preNode.next = node;
this.size++;
}
public void addLast(T t){
add(t, this.size);
}
// 删
public T remove(int index){
if(index < 0 || index > this.size - 1){
throw new IllegalArgumentException("index is error");
}
T data = null;
if(index == 0){
data = head.data;
this.head = head.next;
this.size--;
return data;
}
Node preNode = this.head;
for(int i = 0; i < index - 1; i++){
preNode = preNode.next;
}
Node p = preNode.next;
data = p.data;
preNode.next = p.next;
this.size--;
return data;
}
public void remove(T t){
int index = getIndex(t);
remove(index);
}
// 修改
public T set(int index, T t){
Node p = this.head;
for(int i = 0; i < index; i++){
p = p.next;
}
T oldData = p.data;
p.set(t);
return oldData;
}
// 查
public boolean contains(T t){
Node p = this.head;
while(p != null){
if(p.data.equals(t)) return true;
p = p.next;
}
return false;
}
public int getIndex(T t){
Node p = this.head;
for(int i = 0; i < this.size; i++){
T data = p.data;
if(data.equals(t)) return i;
else p = p.next;
}
return -1;
}
// 遍历
public void display(){
Node p = this.head;
while(p != null){
System.out.println(p.data);
p = p.next;
}
}
public static void main(String[] args){
LinkedList list = new LinkedList<>();
list.addFirst(2);
list.add(1, 1);
list.addLast(5);
list.display();
System.out.println("-------------");
list.remove(1);
list.display();
System.out.println("-------------");
list.set(1, 888);
list.display();
System.out.println(list.contains(88));
}
}