赞
踩
一、链表基本操作
1.单链表
(I)结点定义:单链表中的结点由两部分组成,数据域和指针域。指针域里面存放的是指向下一结点的地址,数据域保存该结点的数据值。单链表结构如图所示:
(II)用Java来定义结点类如下:
class Node{ //结点类
Node next=null; //存储指向后继节点的指针
int data; //存储结点的数据值
public Node(int data){
this.data=data;
}
}
(III)单链表的增删操作图解说明:
增加结点算法思路:假设需要将新值为x的结点插入链表第i个位置,步骤如下:
删除结点算法思路:假设需要删除单链表第i个位置的结点,步骤如下:
(1)先找到第i-1个位置的结点p ;
(2)设置第i-1个位置结点的指针域指向第i+1个位置结点:p.next=p.next.next
删除结点操作示意图如下所示:
(IV)单链表的基本操作Java实现:
public class MyLinkedList{ static Node head=null; //链表头的引用 /* * * 头插法新增节点 */ public static void addNodeHead(int data){ if(head==null){ Node newNode=new Node(data); head=newNode; return; } Node newNode=new Node(data); Node tmp1=head; Node tmp2=tmp1.next; //头节点的下一个节点 tmp1.next=newNode; newNode.next=tmp2; } /* * * 尾插法新增节点 */ public static void addNodeTail(int data){ if(head==null){ //如果没有头节点则创建头节点 Node newNode=new Node(data); head=newNode; return; } Node newNode=new Node(data); Node tmp=head; while (tmp.next!=null){ //遍历找到最后一个节点 tmp=tmp.next; } tmp.next=newNode; } /* * * 在链表中第i个位置插入节点 */ public static void insertNode(int i,int data){ Node newNode=new Node(data); Node tmp=head; if(i==2){ //如果插入的节点位置是第2个 Node node=tmp.next; tmp.next=newNode; newNode.next=node; }else{ int j=1; while (j<=i-2){ //找到第i-1个节点 tmp=tmp.next; j++; } Node node=tmp.next; //第i个节点 tmp.next=newNode; newNode.next=node; } } /* * 删除第i个位置的节点 */ public static void deleteNode(int i){ if(i<1||i>getLength()){ System.out.println("删除节点元素的位置不合理"); } Node tmp=head; if(i==1){ head=head.next; }else if(i==2){ //如果删除结点的位置是第2个 Node tmp1=head.next; Node tmp2=tmp1.next; //第i+1个节点的位置 head.next=tmp2; }else if(i>2){ int j=1; while (j<=i-2){ //找到第i-1个节点 tmp=tmp.next; j++; } Node tmp3=tmp.next.next; //找到第i+1个节点的位置 tmp.next=tmp3; } } /* * * 计算链表的长度 */ public static int getLength(Node head){ Node tmp=head; int length=0; while (tmp!=null){ length++; tmp=tmp.next; } return length; } /* * 对链表进行排序 */ public static void orderLinkedList(){ Node nextNode=null; Node curNode=head; while (curNode!=null){ nextNode=curNode.next; while (nextNode!=null){ if(curNode.data>nextNode.data){ int temp=curNode.data; curNode.data=nextNode.data; nextNode.data=temp; } nextNode=nextNode.next; } curNode=curNode.next; } } /* * * 单链表操作测试程序 */ public static void main(String[] args) { addNode(5); addNode(1); addNode(3); Node tmp=head; insertNode(2,8); insertNode(2,6); System.out.println("LinkedListLength:"+getLength()); while (tmp!=null){ //遍历链表元素 System.out.print(tmp.data+" "); tmp=tmp.next; } orderLinkedList(); Node tmp1=head; System.out.println(); System.out.print("--------------排序后---------------"); System.out.println(); while (tmp1!=null){ System.out.print(tmp1.data+" "); tmp1=tmp1.next; } } } class Node{ //声明节点类 int data; //数据域 Node next; //指针域 public Node(){ } public Node(int data){ this.data=data; } }
2.双向链表与循环链表
(I)结点定义:双向链表是在单链表的基础之上扩展而来的,结点由3部分组成分别为前驱指针域、数据域、后继指针域;前驱指针保存上一个结点的地址信息,后继指针保存下一个结点的地址信息,数据域保存该结点的数据值。双向链表结构如图所示:
(II)用Java来定义结点类如下:
class Node2{ private int data; //数据域 private Node2 next; //后继指针 private Node2 pre; //前驱指针 public Node2(int data){ this.data=data; } public int getData() { return data; } public void setData(int data) { this.data = data; } public Node2 getNext() { return next; } public void setNext(Node2 next) { this.next = next; } public Node2 getPre() { return pre; } public void setPre(Node2 pre) { this.pre = pre; } }
(III)双向链表的增删操作图解说明:
增加结点算法思路:假设需要将新值为x的结点插入链表第i个位置,步骤如下:
删除结点算法思路:假设需要删除双向链表第i个位置的结点,步骤如下:
(IV)双向链表的基本操作Java实现:
public class DLinkedList{ /* * * 向双向链表中指定位置处新增节点 */ public static void addNode2(Node2 node,int i,int data){ Node2 newNode=new Node2(12); Node2 head=node; //获取头节点 if(i<1||i>getLength(node)){ System.out.println("插入的位置不合理"); } //首先得到第i-1个位置 Node2 tmp=head; int j=0; while (i>2){ tmp=tmp.getNext(); i--; } Node2 node2=tmp.getNext(); //得到第i个节点 tmp.setNext(newNode); newNode.setNext(node2); node2.setPre(newNode); newNode.setPre(tmp); } /* * * 从双向链表指定位置中删除节点 */ public static void deleteNode2(Node2 node,int i){ Node2 head=node; //首先得到第i-1个位置 Node2 tmp=head; int j=0; while (i>2){ tmp=tmp.getNext(); i--; } //再得到第i+1个位置 Node2 tmp1=tmp.getNext().getNext(); tmp.setNext(tmp1); tmp1.setPre(tmp); } //计算双向链表的长度 public static int getLength(Node2 node){ Node2 tmp=node; int length=0; while (tmp!=null){ length++; tmp=tmp.getNext(); } return length; } /* * * 测试程序 */ public static void main(String[] args) { Scanner scanner=new Scanner(System.in); /* * * 创建双向链表 */ List<Node2> list=new ArrayList<>(); for (int i = 0; i <5 ; i++) { int j=i+1; Node2 node=new Node2(j*10); list.add(node); } for (int i = 0; i <4 ; i++) { list.get(i).setNext(list.get(i+1)); } for (int i = 4; i >0 ; i--) { list.get(i).setPre(list.get(i-1)); } // list.get(0).setPre(list.get(4)); // list.get(4).setNext(list.get(0)); /* ** 遍历双向链表 */ System.out.print("从前往后遍历结果为:"+" "); Node2 tmp=list.get(0); while(tmp!=null){ System.out.print(tmp.getData()+" "); tmp=tmp.getNext(); } System.out.println(); System.out.print("从后往前遍历结果为:"+" "); Node2 tmp1=list.get(4); while (tmp1!=null){ System.out.print(tmp1.getData()+" "); tmp1=tmp1.getPre(); } System.out.println(); System.out.println("原双向链表的长度为:"+getLength(list.get(0))); System.out.println("请输入要插入元素的位置:"); int i=scanner.nextInt(); System.out.println("-------------------------------新增元素后的双向链表遍历结果为:---------------------------------"); addNode2(list.get(0),i,12); Node2 head=list.get(0); System.out.print("从前往后遍历结果为:"+" "); Node2 backNode=null; while (head!=null){ if(head.getNext()==null){ backNode=head; } System.out.print(head.getData()+" "); head=head.getNext(); } System.out.println(); System.out.print("从后往前遍历结果为:"+" "); while (backNode!=null){ System.out.print(backNode.getData()+" "); backNode=backNode.getPre(); } System.out.println(); System.out.println("请输入要删除的位置:"); int j=scanner.nextInt(); System.out.println("--------------------------------删除元素后的双向链表遍历结果为:----------------------------------"); deleteNode2(list.get(0),j); Node2 head1=list.get(0); System.out.print("从前往后遍历结果为:"+" "); while (head1!=null){ System.out.print(head1.getData()+" "); head1=head1.getNext(); } System.out.println(); System.out.print("从后往前遍历结果为:"+" "); Node2 backNode1=list.get(4); while (backNode1!=null){ System.out.print(backNode1.getData()+" "); backNode1=backNode1.getPre(); } } }
二、栈与队列基本操作
1.栈与队列的特点以及比较
(I)定义:栈与队列是在程序设计中被广泛使用的两种重要的线性数据结构,都是在一个特定范围的存储单元中存储数据。栈的特点是“先进后出,后进先出”,栈这种数据结构最重要并且需要理解的是栈顶指针,其压栈、出栈操作都是移动栈顶指针完成;队列的特点是“先进先出,后进后出”,队列这种数据结构最重要需要理解的是队头指针与队尾指针,其入队、出队操作都是移动队尾指针完成的。栈与队列的数据结构如下图所示:
(II)压栈与出栈操作图解说明:
压栈操作本质是移动栈顶指针的过程,假设需要进栈的元素为x。基于链表实现其步骤如下:
(1)新建一个数据域为x的新结点newNode;
(2)设置栈顶指针newNode.next=top;
(3)设置top=newNode;
压栈操作伪代码如下:
//压栈操作
public void push(E data){
Node<E> newNode=new Node<E>(data);
newNode.next=top;
top=newNode;
}
出栈操作本质也是移动栈顶指针的过程。基于链表的实现其步骤如下:
(1)首先得到栈顶指针指向的结点;
(2)在移动栈顶指针;
出栈操作伪代码如下:
//出栈操作
public E pop(){
if(isEmpty()){
return null;
}
E data=top.data;
top=top.next;
return data;
}
//入队操作
public void put(E data){
Node<E> newNode=new Node<E>(data);
if(head==null && tail==null){
head=tail=newNode;
}else{
tail.next=newNode;
tail=newNode;
}
}
出队操作本质是从队列头指针开始遍历链表的过程。基于链表的实现步骤如下:
(1)首先判断队列是否为空,如果为空则返回null;
(2)从头指针开始依次遍历。
出队操作伪代码如下:
//出队操作
public E pop(){
if(isEmpty()){
return null;
}
E data=head.data;
head=head.next;
return data;
}
package dataStructure; /** * Created by Air on 2019/6/29. * 用链表的方式实现栈 */ public class Stack { static Node1 top=null; //定义栈顶指针 //判断栈是否为空 public static boolean isEmpty(){ return top==null; } //得到栈顶元素的值 public int peek(){ if(isEmpty()){ return 0; } return top.data; } //压栈操作 public static int push(int data){ Node1 newNode=new Node1(data); newNode.next=top; top=newNode; int j=top.data; return data; } //出栈操作 public static int pop(){ if(!isEmpty()){ int data=top.data; top=top.next; return data; } return 0; } //计算栈的长度 public static int getLength(){ int length=0; Node1 tmp=top; while (tmp!=null){ length++; tmp=tmp.next; } return length; } //测试程序 public static void main(String[] args) { Stack stack=new Stack(); for (int i = 0; i <5 ; i++) { stack.push(i+1); } System.out.println("栈的长度为:"+getLength()); System.out.print("出栈顺序为:"); while (top!=null){ System.out.print(top.data+" "); top=top.next; } } } class Node1{ Node1 next=null; //结点的指针域 int data; //结点的数据域 public Node1(int data){ this.data=data; } }
package dataStructure; /** * Created by Air on 2019/6/29. * 使用链表实现队列 */ public class MyQueue<E> { Node2<E> head=null; //定义头指针 Node2<E> tail=null; //定义尾指针 //判断是否为空 public boolean isEmpty(){ if(head==null && tail==null){ return true; }else{ return false; } } //入队操作 public void put(E data){ Node2<E> newNode=new Node2<E>(data); if(isEmpty()){ head=tail=newNode; }else{ tail.next=newNode; tail=newNode; } } //出队操作 public E pop(){ if(isEmpty()){ return null; } E data=head.data; head=head.next; return data; } //计算队列的长度 public int size(){ Node2<E> tmp=head; int length=0; while (tmp!=null){ length++; tmp=tmp.next; } return length; } //测试程序 public static void main(String[] args) { MyQueue<Integer> queue=new MyQueue<Integer>(); for (int i = 0; i < 10; i++) { queue.put(i+1); } System.out.println("队列长度为:"+ queue.size()); System.out.println("出队顺序为:"); for (int i = 0; i <10 ; i++) { System.out.print(queue.pop()+" "); } } } class Node2<E>{ Node2<E> next=null; //定义指针域 E data; //定义数据域 public Node2(E data){ this.data=data; } }
(VI)如何用两个栈模拟队列,示例代码如下:
package dataStructure; /** * Created by Air on 2019/6/30. * 使用两个栈模拟队列操作 */ public class Queue<E> { LStack<E> lStack1=new LStack<>(); LStack<E> lStack2=new LStack<>(); //对lStack1压栈 public void put(E data){ lStack1.push(data); } //出栈操作 public E pop(){ if(lStack2.isEmpty()){ while (!lStack1.isEmpty()){ lStack2.push(lStack1.pop()); } } return lStack2.pop(); } //判空操作 public boolean isEmpty(){ if(lStack1.isEmpty() && lStack2.isEmpty()){ return true; }else{ return false; } } /* * * 测试程序 */ public static void main(String[] args) { Queue<Integer> queue=new Queue<>(); for (int i = 0; i <10 ; i++) { queue.put(i+1); } System.out.print("出队顺序为:"); for (int i = 0; i <10 ; i++) { System.out.print(queue.pop()+" "); } } } /* * * 使用链表实现栈 */ class LStack<E>{ Node3<E> top=null; //定义栈顶指针 /* * * 得到栈顶元素值 */ public E peek(){ if(isEmpty()){ return null; } return top.data; } /* * * 判空操作 */ public boolean isEmpty(){ return top==null; } /* * * 压栈操作 */ public Node3<E> push(E data){ Node3<E> newNode=new Node3<>(data); newNode.next=top; top=newNode; return newNode; } /* * *出栈操作 */ public E pop(){ if(isEmpty()){ return null; } E data=top.data; top=top.next; return data; } /* * * 计算栈的长度 */ public int getLength(){ int length=0; Node3<E> tmp=top; while (tmp!=null){ length++; tmp=tmp.next; } return length; } /* * * 测试栈是否创建成功 */ public static void main(String[] args) { LStack<Integer> lStack=new LStack<>(); lStack.push(1); lStack.push(2); lStack.push(3); System.out.println("新创建的栈的长度为:"+lStack.getLength()); System.out.print("出栈顺序为:"); for (int i = 0; i <3 ; i++) { System.out.print(lStack.pop()+" "); } } } /* * * 定义结点类 */ class Node3<E>{ Node3<E> next=null; //定义结点的指针域 E data; //定义结点的数据域 public Node3(E data){ this.data=data; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。