数据结构包括:线性结构和非线性结构
线性结构:存在一一对应关系,比如数组a[0]=1.(数组,队列,栈,链表)
线性结构有两种存储方式:顺序存储和链式存储,顺序存储称为线性表,存储的元素地址是连续的比如数组。链式存储的线性表称为链表,存储数据不连续,靠地址指针来定位。链式存储适用于在较频繁地插入、删除、更新元素时,而顺序存储结构适用于频繁查询时使用。
非线性结构:二维数组,图,树。
类似管道,先进先出,队列两种实现:数组实现和链表实现
每个节点包括data域和next域
//定义节点
class HeroNode {
public int number;
public String name;
public String nickName;
public HeroNode next;
public HeroNode(int hNumber, String hName, String hNickName) {
this.number = hNumber;
this.name = hName;
this.nickName = hNickName;
}
//重写toString来打印
@Override
public String toString() {
return "Hero: [ number: " + number + ", name: " + name + ", nickName: " + nickName + "]";
}
}
//单链表
class SingleLinkedList {
//先初始化头节点,不存放具体数据
private HeroNode head = new HeroNode(0, "", "");
public HeroNode getHead(){
return this.head;
}
//添加节点到链表尾部
public void add(HeroNode node) {
//使用临时节点
HeroNode temp = head;//temp=head则循环就要加next
//遍历找到尾节点来插入
//当temp的下一个节点为null时说明temp为尾节点
while (temp.next != null) {
temp = temp.next;//后移节点
}
//将最后一个节点指向新节点
temp.next = node;
}
//在特定位置插入节点
public void insert(HeroNode node) {
//创建temp需是在要插入节点的前一个节点
HeroNode temp = head;
//循环直到temp为最后一个节点
while (temp.next != null) {
if (temp.next.number == node.number) {
System.out.println("该节点已存在,不能插入");
return;
}
//遍历查找当temp.next.number > node.number那么就是找到了该节点位置
else if (temp.next.number > node.number) {//找到该节点位置
break;
}
temp = temp.next;
}
//找到之后插入,
node.next = temp.next;
temp.next = node;
}
//更新节点
public void update(HeroNode node) {
//不修改第一个
HeroNode temp = head.next;
boolean flag = false;
//循环直到temp为最后一个节点
while (temp != null) {
if (temp.number == node.number) {
flag = true;
break;
}
temp = temp.next;
}
//如果找到了
if (flag) {
temp.nickName = node.nickName;
temp.name = node.name;
} else {
System.out.println("没有找到该节点。");
}
}
//删除节点
//我们需要找到待删除节点的前一个节点
public void delete(int a) {
HeroNode temp = head;
boolean flag = false;
while (temp.next != null) {
if (temp.next.number == a) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next = temp.next.next;
} else {
System.out.println("要删除的该节点不存在");
}
}
//查
public void get(int a) {
System.out.println("查询编号为:" + a);
HeroNode temp = head.next;
boolean flag = false;
while (temp != null) {
if (temp.number == a) {
flag = true;
break;
}
temp = temp.next;
}
if (flag)
System.out.println(temp);
else
System.out.println("没找到该节点");
}
//打印链表
public void printList() {
System.out.println("printList:");
//先判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
} else {
//头节点不能动,但是头节点数据是0,所以我们给temp作为next
HeroNode temp = head.next;
while (temp != null) {//一直循环直到当temp指向空节点,则跳出循环
System.out.println(temp);
temp = temp.next;
}
}
}
}
//获取单链表有效节点个数
//形参为链表头节点
public static int countNode(HeroNode headNode) {
int length = 0;
//判断是否为空链表
if (headNode.next == null)
return 0;
HeroNode cur = headNode.next;
while (cur != null) {
length++;
cur = cur.next;
}
return length;
}
//查找单链表中倒数第K个节点
//思路:先遍历得到链表长度然后计算处第几个节点
public static HeroNode getReverseNode(HeroNode headNode, int k){
int length = 0;
//判断是否为空链表
if (headNode.next == null)
return null;
//第一次遍历得到节点个数
HeroNode cur = headNode.next;
while (cur != null) {
length++;
cur = cur.next;
}
//第二次遍历得到该节点
if (k<=0 || k>length)
return null;
HeroNode cur2 = headNode.next;
//因为是第几个所有用for循环
for (int i = 0;i<length-k;i++){
cur2 = cur2.next;
}
//for循环移动指针之后这时就指向该节点
return cur2;
}
//链表的反转
//思路:把传进的链表遍历每个节点插入到第二个链表的前端
public static void reverseLinkedList(HeroNode headNode) {
//如果链表为空或者只有一个节点,则直接返回
if (headNode.next == null || headNode.next.next == null) {
return;
}
HeroNode cur = headNode.next;//第一个cur遍历
HeroNode cur2 = null;//第二个cur进行链接后面的表
HeroNode reverseHead = new HeroNode(0, "", "");//反转链表头
while (cur != null) {
//cur2保存临时变量
cur2 = cur.next;
//将节点插入到第二个链表头节点后面
cur.next = reverseHead.next;
reverseHead.next = cur;
//后移cur,这时cur=cur.next已经不能后移了,而需要用到cur2
cur = cur2;
}
//所有节点放到第二个链表中把第一个链表头节点指向第二个链表
headNode.next = reverseHead.next;
}
//链表到逆序打印
//思路:一:我们可以反转链表打印,但会破坏链表结构。二:将链表节点压入一个栈,然后出栈就是逆序。
public static void reversePrint(HeroNode headNode) {
//判断为空
if (headNode.next == null) {
return;
}
//压栈
Stack<HeroNode> heroNodeStack = new Stack<>();
HeroNode cur = headNode.next;
while (cur != null) {
heroNodeStack.add(cur);
cur = cur.next;
}
//打印栈
while (heroNodeStack.size() > 0) {
System.out.println(heroNodeStack.pop());
}
}
单链表只能一个方向查找且删除的时候需要靠辅助节点;
双向链表可以两个方向查找,且删除的时候可以自己删除。
package DataStructure;
import java.util.Stack;
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode node1 = new HeroNode(1, "song", "ji");
HeroNode node2 = new HeroNode(2, "lujunyi", "yu");
HeroNode node3 = new HeroNode(3, "wuyong", "zhiduoxing");
HeroNode node4 = new HeroNode(4, "gongsunsheng", "ruyunlong");
HeroNode node5 = new HeroNode(3, "duyongxing", "zhid");
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.add(node1);
singleLinkedList.add(node2);
singleLinkedList.add(node3);//不要同一个对象添加两次
singleLinkedList.insert(node4);
singleLinkedList.printList();
singleLinkedList.update(node5);
singleLinkedList.printList();
singleLinkedList.delete(4);
singleLinkedList.printList();
singleLinkedList.get(1);
System.out.println(countNode(singleLinkedList.getHead()));
System.out.println(getReverseNode(singleLinkedList.getHead(), 5));
reversePrint(singleLinkedList.getHead());
}
//获取单链表有效节点个数
//形参为链表头节点
public static int countNode(HeroNode headNode) {
int length = 0;
//判断是否为空链表
if (headNode.next == null)
return 0;
HeroNode cur = headNode.next;
while (cur != null) {
length++;
cur = cur.next;
}
return length;
}
//查找单链表中倒数第K个节点
//思路:先遍历得到链表长度然后计算处第几个节点
public static HeroNode getReverseNode(HeroNode headNode, int k) {
int length = 0;
//判断是否为空链表
if (headNode.next == null)
return null;
//第一次遍历得到节点个数
HeroNode cur = headNode.next;
while (cur != null) {
length++;
cur = cur.next;
}
//第二次遍历得到该节点
if (k <= 0 || k > length)
return null;
HeroNode cur2 = headNode.next;
//因为是第几个所有用for循环
for (int i = 0; i < length - k; i++) {
cur2 = cur2.next;
}
//for循环移动指针之后这时就指向该节点
return cur2;
}
//链表的反转
//思路:把传进的链表遍历每个节点插入到第二个链表的前端
public static void reverseLinkedList(HeroNode headNode) {
//如果链表为空或者只有一个节点,则直接返回
if (headNode.next == null || headNode.next.next == null) {
return;
}
HeroNode cur = headNode.next;//第一个cur遍历
HeroNode cur2 = null;//第二个cur进行链接后面的表
HeroNode reverseHead = new HeroNode(0, "", "");//反转链表头
while (cur != null) {
//cur2保存临时变量
cur2 = cur.next;
//将节点插入到第二个链表头节点后面
cur.next = reverseHead.next;
reverseHead.next = cur;
//后移cur,这时cur=cur.next已经不能后移了,而需要用到cur2
cur = cur2;
}
//所有节点放到第二个链表中把第一个链表头节点指向第二个链表
headNode.next = reverseHead.next;
}
//链表到逆序打印
//思路:一:我们可以反转链表打印,但会破坏链表结构。二:将链表节点压入一个栈,然后出栈就是逆序。
public static void reversePrint(HeroNode headNode) {
//判断为空
if (headNode.next == null) {
return;
}
//压栈
Stack<HeroNode> heroNodeStack = new Stack<>();
HeroNode cur = headNode.next;
while (cur != null) {
heroNodeStack.add(cur);
cur = cur.next;
}
//打印栈
while (heroNodeStack.size() > 0) {
System.out.println(heroNodeStack.pop());
}
}
}
//单链表
class SingleLinkedList {
//先初始化头节点,不存放具体数据
private HeroNode head = new HeroNode(0, "", "");
public HeroNode getHead() {
return this.head;
}
//添加节点到链表尾部
public void add(HeroNode node) {
//使用临时节点
HeroNode temp = head;//temp=head则循环就要加next
//遍历找到尾节点来插入
//当temp的下一个节点为null时说明temp为尾节点
while (temp.next != null) {
temp = temp.next;//后移节点
}
//将最后一个节点指向新节点
temp.next = node;
}
//在特定位置插入节点
public void insert(HeroNode node) {
//创建temp需是在要插入节点的前一个节点
HeroNode temp = head;
//循环直到temp为最后一个节点
while (temp.next != null) {
if (temp.next.number == node.number) {
System.out.println("该节点已存在,不能插入");
return;
}
//遍历查找当temp.next.number > node.number那么就是找到了该节点位置
else if (temp.next.number > node.number) {//找到该节点位置
break;
}
temp = temp.next;
}
//找到之后插入,
node.next = temp.next;
temp.next = node;
}
//更新节点
public void update(HeroNode node) {
//不修改第一个
HeroNode temp = head.next;
boolean flag = false;
//循环直到temp为最后一个节点
while (temp != null) {
if (temp.number == node.number) {
flag = true;
break;
}
temp = temp.next;
}
//如果找到了
if (flag) {
temp.nickName = node.nickName;
temp.name = node.name;
} else {
System.out.println("没有找到该节点。");
}
}
//删除节点
//我们需要找到待删除节点的前一个节点
public void delete(int a) {
HeroNode temp = head;
boolean flag = false;
while (temp.next != null) {
if (temp.next.number == a) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next = temp.next.next;
} else {
System.out.println("要删除的该节点不存在");
}
}
//查
public void get(int a) {
System.out.println("查询编号为:" + a);
HeroNode temp = head.next;
boolean flag = false;
while (temp != null) {
if (temp.number == a) {
flag = true;
break;
}
temp = temp.next;
}
if (flag)
System.out.println(temp);
else
System.out.println("没找到该节点");
}
//打印链表
public void printList() {
System.out.println("printList:");
//先判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
} else {
//头节点不能动,但是头节点数据是0,所以我们给temp作为next
HeroNode temp = head.next;
while (temp != null) {//一直循环直到当temp指向空节点,则跳出循环
System.out.println(temp);
temp = temp.next;
}
}
}
}
//定义节点
class HeroNode {
public int number;
public String name;
public String nickName;
public HeroNode next;
public HeroNode(int hNumber, String hName, String hNickName) {
this.number = hNumber;
this.name = hName;
this.nickName = hNickName;
}
//重写toString来打印
@Override
public String toString() {
return "Hero: [ number: " + number + ", name: " + name + ", nickName: " + nickName + "]";
}
}