数据结构——线性表

  • 2019 年 10 月 6 日
  • 筆記

什么是线性表?

线性表是具有相同类型的n个元素(n>=0)的有限序列

1.顺序表

  • 线性表采用顺序存储方式
  • 其逻辑顺序和物理顺序相同

问题:需要连续存储空间,插入等操作需要移动大量元素,时间复杂度高。

2.单链表

线性表采用链式存储方式称为单链表。

链式存储是采用节点来进行存储的。

每个节点包括data域和next域。(不一定连续存储)

  • 单链表反转
  • 单链表的增删改查
  • 约瑟夫环

单链表反转

单链表的增删改查

import java.util.Stack;    //定义单个节点  class Node  {        public String data;  //定义数据节点        public Node next;   //定义指向下一个节点的指针        public Node() {      }        public Node(String data) {          this.data = data;      }        public String getData() {          return data;      }        public void setData(String data) {          this.data = data;      }        public Node getNext() {          return next;      }        public void setNext(Node next) {          this.next = next;      }        @Override      public String toString() {          return "Note{" +                  "data='" + data + ''' +                  '}';      }  }      public class Operation  {      //初始化头结点      private static Node head = new Node();          private static Node reverseHead = new Node();          //插入节点(头插)      public void insertToHead(Node node)      {          Node temp = head;            //头插法需要设置head.next和node.next的值。其中nodeNext指向headNext,而headNext指向node。          //由于是赋值的关系,二者顺序不可颠倒          node.next=temp.next;          temp.next=node;      }        //插入节点(尾插)      public void insertToLast(Node node)      {          Node temp = head;            while (true)          {              if(temp.next==null)              {break;}              temp=temp.next;          }          temp.next=node;      }        //插入节点(指定位置k之后)        public void insertToK(Node node,int k)      {          Node temp = head;          for(int i=0;i<k;i++)          {              temp=temp.next;          }          node.next=temp.next;          temp.next=node;      }          //删除第m个节点      public void deleteM(int m)      {          Node temp = head;          for(int i=0;i<m-1;i++)          {              temp=temp.next;          }          temp.next=temp.next.next;      }          //修改第n个节点(n)      public void updateN(int n)      {          Node temp = head;          for(int i=0;i<n;i++)          {              temp=temp.next;          }          temp.data="up";      }          //递归反转        public Node reverseLinkedList(Node node) {          if (node == null || node.next == null) {              return node;          } else {              Node headNode = reverseLinkedList(node.next);              node.next.next = node;              node.next = null;              return headNode;          }      }        //遍历反转      public Node reserveByFor(Node head)      {          Node cur = head.next;          Node next = null;          Node Rhead = new Node();              while(true)          {              if(cur==null)              {                  break;              }              else              {                  next=cur.next;                  cur.next=Rhead.next;                  Rhead.next=cur;                    cur=next;              }          }            head.next=Rhead.next;            return head;      }        //print(last to first)      public void printLtoF(Node head)      {          Stack<Node>stack = new Stack<>();          Node cur = head.next;          while (cur!=null)          {              stack.push(cur);              cur=cur.next;          }          while (stack.size()>0)          {              System.out.println(stack.pop());          }      }              public static void main(String[] args)      {          Operation operation = new Operation();            operation.insertToHead(new Node("A"));          operation.insertToHead(new Node("B"));          operation.insertToHead(new Node("C"));            operation.insertToLast(new Node("1"));          operation.insertToLast(new Node("2"));          operation.insertToLast(new Node("3"));    //        operation.insertToK(new Node("k"),2);    //        operation.deleteM(3);    //        operation.updateN(1);              Node temp =head;          //遍历链表          while(true)          {              if(temp.next==null)              {break;}              else              {                  temp=temp.next;                  System.out.println(temp.toString());                }          }                System.out.println("//1.求单链表中有效节点个数.");            temp=head;          int count=0;          while(true)          {              if(temp.next==null)              {break;}              else              {                  temp=temp.next;                  count++;              }          }          System.out.println(count);              System.out.println("//2.查找单链表中倒数第K=3个节点");            temp=head;            //获取链表总长          int length=0;            while (true)          {              if(temp.next==null)              {break;}              else              {                  temp=temp.next;                  length++;              }          }              temp=head;          for(int i=0;i<length-2;i++)          {              temp=temp.next;          }          System.out.println(temp.data);              System.out.println("3.实现单链表的反转");    //      temp=operation.reverseLinkedList(head);              temp = operation.reserveByFor(head);            //遍历链表          while(true)          {              if(temp.next==null)              {break;}              else              {                  temp=temp.next;                  System.out.println(temp.toString());              }          }              System.out.println("4.从尾到头打印单链表");            temp = head;          operation.printLtoF(temp);                  }  }

单向环形链表输出约瑟夫环

//定义单个节点  class Node  {        public String data;  //定义数据节点        public Node next;   //定义指向下一个节点的指针          public Node() {      }        public Node(String data) {          this.data = data;      }          @Override      public String toString() {          return "Note{" +                  "data='" + data + ''' +                  '}';      }      }      public class Operation  {      //初始化头结点      private static Node head = new Node();        //尾插法      public void add(Node node)      {          Node temp = head;            while (true)          {              if(temp.next==null)              {break;}              temp=temp.next;          }          temp.next=node;      }        //创建单向环形链表      public Node createCircle(int n)      {          //创建单链表          for(int i=0;i<n;i++)          {              add(new Node("No:"+(i+1)));          }            //遍历链表          Node temp = head;          while(temp.next!=null)          {              temp=temp.next;              System.out.println(temp);          }            Node last = temp;          temp=head;          last.next=head.next;   //连接首尾            System.out.println("last为最后一个数5:");          System.out.println(last);              System.out.println("循环两遍单向环形链表:");          int count=2*n;          while(last!=null)          {              if(count==0)              {                  break;              }              System.out.println(last.next);              last=last.next;              count--;          }          System.out.println("last="+last.data);          return last;      }        public static void JosephusProblem(int n, int k, int m, Node last)      {          //定位到第k个节点,输出k+1个节点并删除,并让last定位到第k个节点            Node temp = last;          for(int i=0;i<k;i++)  //定位到第k个节点          {              temp=temp.next;          }          System.out.println("第一次输出"+temp.next.data);//输出            temp.next=temp.next.next; //删除第K+1个节点          last=temp.next;                for(int i=0;i<n-1;i++)          {              temp=last;                System.out.println("第二次输出"+temp.next.data);                temp.next=temp.next.next;              last=temp.next;          }          }      public static void main(String[] args)      {          Operation operation = new Operation();            //定义人数          int n=5;          Node last = operation.createCircle(n);              //定义从第几个节点开始数          int k=1;          //定义数的次数          int m=2;              System.out.println("输出约瑟夫环:");          JosephusProblem(n,k,m,last);          }  }

3.双向链表

双向链表与单向链表的区别

单向列表只能从前往后查找,而双向链表可以向前向后查找。 单向链表删除节点需要依靠辅助节点,而双向链表可以实现自我删除。

双向链表与单项列表的实际区别在于多了一个pre域。

双向链表增删改查

import java.util.Stack;    //定义单个节点  class Node  {        public String data;  //定义数据节点        public Node next;   //定义指向下一个节点的指针        public Node pre;    //定义指向上一个节点的指针        public Node() {      }        public Node(String data) {          this.data = data;      }          @Override      public String toString() {          return "Note{" +                  "data='" + data + ''' +                  '}';      }  }      public class Operation  {      //初始化头结点      private static Node head = new Node();          //插入节点(尾插法)      public void addNode(Node node)      {          Node temp = head;          while(true)          {              if(temp.next==null)              {                  break;              }              temp=temp.next;          }          temp.next=node;          node.pre=temp;      }        //插入节点(头插法)      public void addNodeToHead(Node node)      {          Node temp = head;              node.pre=temp;          node.next=temp.next;          temp.next.pre=node;          temp.next=node;      }        //插入到第k个节点后      public void addToK(Node node,int k)      {          Node temp = head;          for(int i=0;i<k;i++)          {              temp=temp.next;          }          //先建立单链表联系          node.next=temp.next;          temp.next=node;          //建立pre指向          node.pre=temp;          node.next.pre=node;      }        //删除第n个结点      public void deleteNode(int n)      {          Node temp = head;          for(int i=0;i<n;i++)          {              temp=temp.next;          }          temp.next.pre=temp.pre;          temp.pre.next=temp.next;      }        public void list()      {          //遍历链表          Node temp = head;          while(temp.next!=null)          {              temp=temp.next;              System.out.println(temp.toString());          }          System.out.println("=============");      }          //修改第m个结点      public void update(int m)      {          Node temp = head;          for(int i=0;i<m;i++)          {              temp=temp.next;          }          temp.data="up";      }        public static void main(String[] args)      {          Operation operation = new Operation();            operation.addNode(new Node("A"));          operation.addNode(new Node("B"));          operation.addNode(new Node("C"));          operation.addNode(new Node("D"));          operation.addNodeToHead(new Node("head1"));          operation.addNodeToHead(new Node("head2"));          operation.addNodeToHead(new Node("head3"));            //遍历链表          operation.list();            System.out.println("删除第n个节点");          operation.deleteNode(3);            //遍历链表          operation.list();            System.out.println("修改第m个节点");            operation.update(3);            operation.list();            System.out.println("插入到第k个节点后");          operation.addToK(new Node("k" ),3);            operation.list();      }  }