数据结构与算法(Java实现)之 【数组和链表总结】

1、线性表的特征

线性表中每个数据元素有且仅有一个直接前驱和一个直接后继,第一个结点无前驱,最后一个结点无后继。
在这里插入图片描述

2、线性表的存储方式

  • 线性表顺序存储(顺序表):静态分配,借助高级语言的数组,连续的地址空间存放表元素,逻辑关系隐含在存储顺序中。

  • 线性表链式存储(链表):动态分配,借助高级语言的指针,动态申请与动态释放地址空间,结点的物理存储可以是不连续的,逻辑关系通过指针表明。

3、顺序表与链表

在这里插入图片描述
在这里插入图片描述

4、顺序表与链表的比较

(1)、基于空间的考虑

在这里插入图片描述

(2)、基于时间的考虑

在这里插入图片描述

5、各种链表的比较

在这里插入图片描述

6、线性表案例

(1)一元多项式的表示的相加

在这里插入图片描述
在这里插入图片描述

Java代码(参考别人的,知道算法思想就好,没必要自己再写一遍)

// 节点类
class PolynomialNode {
    private int coef;// 存储的一元多项式的系数
    private int expon;// 存储的一元多项式的指数
    private PolynomialNode next;// 下一个结点引用指针

    public PolynomialNode() {
        super();
    }

    public PolynomialNode(int coef, int expon, PolynomialNode next) {
        super();
        this.coef = coef;
        this.expon = expon;
        this.next = next;
    }

    public int getCoef() {
        return coef;
    }

    public void setCoef(int coef) {
        this.coef = coef;
    }

    public int getExpon() {
        return expon;
    }

    public void setExpon(int expon) {
        this.expon = expon;
    }

    public PolynomialNode getNext() {
        return next;
    }

    public void setNext(PolynomialNode next) {
        this.next = next;
    }
}

public class OneVariablePolynomialDemo {
    /**
     * 判断两个指数谁大
     *
     * @param e1 指数1
     * @param e2 指数2
     * @return 如果e1>e2返回1,如果e1<e2返回-1,如果e1=e2返回0
     */
    private static int compare(int e1, int e2) {
        // 比较两项指数e1和e2,根据大小等三种情况返回1、-1,0
        if (e1 > e2) {
            return 1;
        } else if (e1 < e2) {
            return -1;
        } else {
            return 0;
        }
    }

    /**
     * 添加新结点到结果链表
     *
     * @param coef     系数
     * @param expon    指数
     * @param rearNode 结果链表
     * @return 返回添加成功的结果链表
     */
    public static PolynomialNode attach(int coef, int expon, PolynomialNode rearNode) {
        // 创建一个新结点并存储指数项和系数项
        PolynomialNode newNode = new PolynomialNode();
        newNode.setCoef(coef);
        newNode.setExpon(expon);
        newNode.setNext(null);
        // 将新结点插入到当前结果表达式的后面,现在尾结点变成了newNode
        rearNode.setNext(newNode);
        // 将尾结点指向新插入的结点newNode
        rearNode = newNode;
        // 返回链表
        return rearNode;
    }

    /**
     * * 输入的各种情况:
     * * (1)如果系数为1,则不输出系数;(需要判断指数是否为1或者为0亦或者为负数的情况)
     * * (2)如果系数为0,则不输出任何;
     * * (3)如果系数小于0,则在括号内输出负数;(需要判断指数是否为1或者为0亦或者为负数的情况)
     * * (4)如果指数为1,则不输出指数;
     * * (5)如果指数为0并且系数不为0则输出系数;
     * * (6)如果指数是负数则在括号内输出负数;
     *
     * @param node 要打印的结点
     */
    public static void printNode(PolynomialNode node) {
        String polynomial = "";
        // 循环链表
        while (node != null) {
            // 判断系数和指数
            if (node.getCoef() == 1) {
                if (node.getExpon() == 1) {
                    polynomial += "+x";
                } else if (node.getExpon() == 0) {
                    polynomial += "+" + node.getCoef();
                } else if (node.getExpon() < 0) {
                    polynomial += "+" + node.getCoef() + "x^(" + node.getExpon() + ")";
                } else {
                    polynomial += "+" + "x^" + node.getExpon();
                }
            } else if (node.getCoef() == 0) {
                polynomial += "";
            } else if (node.getCoef() < 0) {
                if (node.getExpon() == 1) {
                    polynomial += "+(" + node.getCoef() + ")x";
                } else if (node.getExpon() == 0) {
                    polynomial += "+(" + node.getCoef() + ")";
                } else if (node.getExpon() < 0) {
                    polynomial += "+(" + node.getCoef() + ")x^(" + node.getExpon() + ")";
                } else {
                    polynomial += "+(" + node.getCoef() + ")x^" + node.getExpon();
                }
            } else {
                if (node.getExpon() == 1) {
                    polynomial += "+" + node.getCoef() + "x";
                } else if (node.getExpon() == 0) {
                    polynomial += "+" + node.getCoef();
                } else if (node.getExpon() < 0) {
                    polynomial += "+" + node.getCoef() + "x^(" + node.getExpon() + ")";
                } else {
                    polynomial += "+" + node.getCoef() + "x^" + node.getExpon();
                }
            }
            node = node.getNext();
        }
        System.out.println(polynomial.substring(1, polynomial.length()));
    }

    /**
     * 一元多项式相加
     *
     * @param p1 一元多项式链表1
     * @param p2 一元多项式链表2
     * @return 返回相加的结果
     */
    public static PolynomialNode polyAdd(PolynomialNode p1, PolynomialNode p2) {
        PolynomialNode front, rear, temp;
        int sum;
        // 为方便表头插入,先产生一个临时空结点作为结果多项式链表头
        rear = new PolynomialNode();
        // 由front记录结果多项式头结点
        front = rear;
        // 当两个多项式都有非零项待处理时
        while (p1 != null && p2 != null) {
            // 根据比较结点的指数返回的值进行操作
            switch (compare(p1.getExpon(), p2.getExpon())) {
                // P1中的数据项指数较大时
                case 1:
                    // 将P1的结点放到结果链表中并返回成功的结果链表
                    rear = attach(p1.getCoef(), p1.getExpon(), rear);
                    // 并将P1结点指向它的下一个结点
                    p1 = p1.getNext();
                    break;
                // P2中的数据项指数较大时
                case -1:
                    // 将P2的结点放到结果链表中并返回成功的结果链表
                    rear = attach(p2.getCoef(), p2.getExpon(), rear);
                    // 将P2结点指向它的下一个结点
                    p2 = p2.getNext();
                    break;
                // 两数据项指数相等
                case 0:
                    // 当指数相等时,让系数相加
                    sum = p1.getCoef() + p2.getCoef();
                    // 如果相加的系数不为0(大于或小于0都可)
                    if (sum != 0) {
                        //将该结点放到结果链表中并返回成功的结果链表
                        rear = attach(sum, p1.getExpon(), rear);
                    }
                    // 让P1结点和P2结点都指向下一个结点元素
                    p1 = p1.getNext();
                    p2 = p2.getNext();
                    break;
                default:
                    break;
            }
        }
        // 将未处理完的另一个多项式的所有结点依次复制到结果链表中
        for (; p1 != null; p1 = p1.getNext()) {
            rear = attach(p1.getCoef(), p1.getExpon(), rear);
        }
        for (; p2 != null; p2 = p2.getNext()) {
            rear = attach(p2.getCoef(), p2.getExpon(), rear);
        }
        rear.setNext(null);
        temp = front;
        // 使front指向结果多项式的第一个非零项
        front = front.getNext();
        return front;
    }

    public static void main(String[] args) {
        // 注意:一元多项式的各项要按照指数递减的顺序排列各项
        Scanner scanner = new Scanner(System.in);

        // 获取第一个多项式链表
        System.out.println("【注意:一元多项式的各项要按照指数递减的顺序排列各项】");
        System.out.print("请输入第一个多项式的项数:");
        PolynomialNode p1 = new PolynomialNode();
        // 保存头结点
        PolynomialNode front1 = p1;
        // 获取第一个多项式的项数
        int itemCount = scanner.nextInt();
        // 循环获取多项式的系数和指数
        for (int i = 1; i <= itemCount; i++) {
            System.out.print("第" + i + "项的系数是:");
            int coef = scanner.nextInt();
            System.out.print("第" + i + "项的指数是:");
            int expon = scanner.nextInt();
            // 创建新结点,将数据赋给结点元素
            PolynomialNode p = new PolynomialNode(coef, expon, null);
            p1.setNext(p);
            p1 = p;
        }
        // 打印第一个多项式
        System.out.print("p1(x)=");
        printNode(front1);

        // 获取第二个多项式链表
        System.out.print("请输入第二个多项式的项数:");
        PolynomialNode p2 = new PolynomialNode();
        // 保存头结点
        PolynomialNode front2 = p2;
        // 获取第二个多项式的项数
        int itemCount2 = scanner.nextInt();
        // 循环获取多项式的系数和指数
        for (int i = 1; i <= itemCount2; i++) {
            System.out.print("第" + i + "项的系数是:");
            int coef = scanner.nextInt();
            System.out.print("第" + i + "项的指数是:");
            int expon = scanner.nextInt();
            PolynomialNode p = new PolynomialNode(coef, expon, null);
            p2.setNext(p);
            p2 = p;
        }
        // 打印第一个多项式
        System.out.print("p2(x)=");
        printNode(front2);

        // 计算两个一元多项式相加
        System.out.print("p1(x)+p2(x)=");
        printNode(polyAdd(front1, front2));
    }
}

测试

在这里插入图片描述
代码还有可以改进的地方,比如可以不需要提前输入项数,和多项式的各项不需要要按照指数递减的顺序排列各项

7、纸质练习题

单选题

1、某线性表最常用的操作是取第i个元素和找第i个元素的前驱元素,采用()存储方式最省时间
A、单链表
B、顺序表
C、双链表
D、单循环链表

2、双向链表存储结构中,删除s所指的节点时需修改指针()

A、s->next=s->next->next;s->next->prior=s;

B、s->prior->next=s;s->prior=s->prior->prior;

C、s->prior=s->next->next;s->next=s->prior->prior;

D、s->prior->next=s->next;s->next->prior=s->prior;

3、在双向循环链表中,在p指针所指的节点后插入q所指向的新节点,其修改指针的操作是()

A、p->next=q;q->prior=p;p->next->prior=q;q->next=q;

B、p->next->prior=q;q->next=p->next;q->prior=p;p->next=q;

C、p->next=q;p->next->prior=q;q->prior=p;q->next=p->next;

D、q->prior=p;q->next=p->next;p->next=q;p->next->prior=q;

4、执行下面程序段时,语句s的执行次数为()
for(i=0;i<=n;i++)
for(j=0;j<=i;j++){
s;
}
A、n的平方
B、n的平方 / 2
C、n(n+1)
D、(n+1)(n+2)/2

在这里插入图片描述
6、顺序表的存储密度()

A、大于1
B、等于1
C、小于1
D、不能确定

多选题

1、算法的设计要求是()

A、可行性
B、有限性
C、正确性
D、可读性
E、健壮性
F、高效率和低存储量

填空题

1、带头结点的单链表L中,利用头插法插入节点s,语序序列是( )( )
提示: 用下面的表达式
s->next
L->next
s
L

判断题

1、双向链表中,节点前插入节点,最重要的是p->prior这条关系线,应该放最后修改。

2、线性结构只能用顺序结构来存放,非线性结构只能用非顺序结构来存放。
3、顺序存储方式的优点是存储密度大,且插入、删除操作效率高。

4、链式存储方式的优点是存储密度大,接近于1,且插入、删除操作效率高。

简答题

1、在双向循环链表中,在p指针所指的节点前插入q所指向的新节点,其修改指针的操作(可以画图)
2、头指针、头结点、首元结点的区别是?
3、单链表L中,若要删除由指针q所指向节点的后继节点,借助空指针s,语句序列是什么?(看画图)

答案:
1、选择题 BDBDDB
第四题
在这里插入图片描述
2、多选题 CDEF
3、填空题
第一空: s->next=L->next;
第二空: L->next=s;

3、判断题
√ × × ×

4、简答题
(1)
在这里插入图片描述
(2)头指针、头结点、首元结点的区别是?

正确答案:

头指针是指向头结点的指针

头节点是指链表中的第一个节点,头结点不一定是首元节点

首元节点是链表中的第一个元素节点

(3)
s=q->next;
q->next=s->next;
delete s;
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高高飞起的勇敢麦当

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值