所谓的线性表即每个数据元素具有确定的位置,数据得组织方式又有顺序存储和链式存储,接下来我们线性表中的顺序表及链表的就地逆序问题进行讨论:
1.对于线性表中的顺序存储
比较容易理解的写法:
public void inverseSqList() {
Object temp;//定义交换变量
for (int i = 0; i < curLen/2; i++) {
//将a[0]与a[n]进行交换 然后是a[1]与a[n-1]交换,以此类推,进行顺序表的长度的一半次运算
temp = listElem[i];
listElem[i] = listElem[curLen-i-1];
listElem[curLen-i-1] = temp;
}
}
另一种写法:
public void inverseSqList() {
Object temp;
for (int i = 0,j = curLen -1; i < j; i++,j--) {
temp = listElem[i];
listElem[i] = listElem[j];
listElem[j] = temp;
}
}
2.对于线性表中的链式存储
1.不带头结点单链表的就地逆序:
节点类的定义方式:
class Node<T> {
T data;
Node<T> next;
Node(T data, Node<T> next){
this.data = data;
this.next = next;
}
}
public void inverseLinkList() {
//单链表为空或只有一个元素,不用进行逆置操作
if(head == null || head.next == null )
return ;
//定义三个指针;
Node<T> p = head;//令p为头指针,先指向第0个元素
Node<T> q = head.next;//令q先指向第1个元素
Node<T> t = null;//令t为空作为交换元素
while(q != null) {
t = q.next;
q.next = p;
p = q;
q = t;
}
head.next = null;//令交换后的最后一个元素指向空;
head = p;//交换后的第0个元素的头设置为P
}
下面的草图作为辅助理解的方式:
2.带头结点单链表的就地逆序:
节点类定义:
class Node<T>{
T data;
Node<T> next;
Node(T data, Node<T> next){
this.data = data;
this.next = next;
}
}
构造方法:
LinkListWithHeadNode(){
head = new Node<>(null,null);
size = 0;
}
public void inverseLinkList() {
//单链表为空或只有头结点或只有一个元素,不用进行逆置操作
if(head == null || head.next == null || head.next.next == null )
return;
//定义三个指针:
Node<T> p = head.next;//P先指向第0个元素
Node<T> q = head.next.next;//q先指向第二个元素
Node<T> t = null;//作为交换指针
while(q != null) {
t = q.next;
q.next = p;
p = q;
q = t;
}
head.next.next = null;//令交换后的最后一个元素指向空;
head.next = p;//交换后的第0个元素的头设置为P
}
3.带头结点循环链表的就地逆置:
节点类定义:
class Node<T> {
T data;
Node<T> next;
Node(T data, Node<T> next){
this.data = data;
this.next = next;
}
}
构造方法:
CircularLinkListWithHeadNode() {
head = new Node<>(null, null);
head.next = head;//循环
size = 0;
}
public void inverseCircularLinkListWithHeadNode() {
//单链表为空或只有头结点或只有一个元素,不用进行逆置操作
if(head == null || head.next == head || head.next.next == head )
return;
Node<T> p = head.next;
Node<T> q = head.next.next;
Node<T> t = null;
while(q != head) {
t = q.next;
q.next = p;
p = q;
q = t;
}
head.next.next = head;//令交换后的最后一个元素指向头节点
head.next = p;
}
带头结点循环链表的就地逆置与带头结点的单链表的就地逆置没有太多的差别,只是最后 ‘交换后的最后一个元素指向头节点’循环起来就可以了;
4.带头结点双向链表(设置head和tail,分别指向第1个和最后1个结点)的就地逆置:
节点类,采用的是内部类:
static class Node<T>{
private T data;
Node<T> leftEnd;
Node<T> rightEnd;
private Node(T data, Node<T> leftEnd,Node<T> rightEnd){
this.data = data;
this.leftEnd = leftEnd;
this.rightEnd = rightEnd;
}
}
public void inverseDoubleLinkList() {
//单链表为空或只有头结点或只有一个元素,不用进行逆置操作
if(head == null || head.rightEnd == null)
return;
Node<T> p = head;
Node<T> q = head.rightEnd;
Node<T> t = null;
while(q != null) {
t = q.rightEnd;
q.rightEnd = p;
p = q;
q = t;
}
head.rightEnd = null;
tail = head;
head = p;
return;
}
不带头结点双向链表的就地逆置与不带头结点的单链表的就地逆置没有太多的差别,只是最后 ‘交换后的最后一个元素右节点指空’然后,头尾在交换就可以了。