单链表的简单操作与演示

单链表的简单操作与演示

单链表

单链表概念和简单的设计

单链表是一种链式存取的数据结构,链表中的数据是以结点来表示的,每个结点由元素和指针构成。

元素表示数据元素的映象,就是存储数据的存储单元;指针指示出后继元素存储位置,就是连接每个结点的地址数据。

以结点的序列表示的线性表称作线性链表,也就是单链表,单链表是链式存取的结构。

对于链表的每一个结点,我们使用结构体进行设计,其主要内容有:

img

其中,DATA数据元素,可以为你想要储存的任何数据格式,可以是数组,可以是int,甚至可以是结构体(这就是传说中的结构体套结构体)

NEXT为一个指针,其代表了一个可以指向的区域,通常是用来指向下一个结点,链表的尾部NEXT指向NULL(空),因为尾部没有任何可以指向的空间了

故,对于一个单链表的结点定义,可以代码描述成:

//定义结点类型typedefstructNode {int data; //数据类型,你可以把int型的data换成任意数据类型,包括结构体struct等复合类型structNode *next;//单链表的指针域} Node,*LinkedList; //Node表示结点的类型,LinkedList表示指向Node结点类型的指针类型

链表的初始化

初始化主要完成以下工作:创建一个单链表的前置节点并向后逐步添加节点,一般指的是申请结点的空间,同时对一个结点赋空值(NULL),其代码可以表示为:

LinkedList listinit(){Node L; L=(Node)malloc(sizeof(Node)); //开辟空间 if(L==NULL){ //判断是否开辟空间失败,这一步很有必要printf(“申请空间失败”);//exit(0); //开辟空间失败可以考虑直接结束程序 } L->next=NULL; //指针指向空}

注意:一定要判断是否开辟空间失败,否则生产中由于未知的情况造成空间开辟失败,仍然在继续执行代码,后果将不堪设想啦,因此养成这样的判断是很有必要的。

头插入法创建单链表

利用指针指向下一个结点元素的方式进行逐个创建,使用头插入法最终得到的结果是逆序的。如图所示:

img

从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后。

//头插法建立单链表LinkedList LinkedListCreatH(){Node *L; L = (Node *)malloc(sizeof(Node)); //申请头结点空间 L->next = NULL; //初始化一个空链表int x; //x为链表数据域中的数据while(scanf(“%d”,&x) != EOF) { Node *p; p = (Node *)malloc(sizeof(Node)); //申请新的结点 p->data = x; //结点数据域赋值 p->next = L->next; /将结点插入到表头L–>|2|–>|1|–>NULL L->next = p; }return L;}

插入法创建单链表

如图所示为尾插入法的创建过程。

img

头插法生成的链表中,结点的次序和输入数据的顺序不一致。若希望两者次序一致,则需要尾插法。

该方法是将新结点逐个插入到当前链表的表尾上,为此必须增加一个尾指针r, 使其始终指向当前链表的尾结点,代码如下:

//尾插法建立单链表LinkedList LinkedListCreatT(){Node *L; L = (Node *)malloc(sizeof(Node)); //申请头结点空间 L->next = NULL; //初始化一个空链表 Node *r; r = L; //r始终指向终端结点,开始时指向头结点int x; //x为链表数据域中的数据while(scanf(“%d”,&x) != EOF) { Node *p; p = (Node *)malloc(sizeof(Node)); //申请新的结点 p->data = x; //结点数据域赋值 r->next = p; //将结点插入到表头L–>|1|–>|2|–>NULL r = p; } r->next = NULL;return L;}

遍历单链表如打印、修改

从链表的头开始,逐步向后进行每一个元素的访问,称为遍历。

对于遍历操作,我们可以衍生出很多常用的数据操作,比如查询元素,修改元素,获取元素个数,打印整个链表数据等等。

进行遍历的思路极其简单,只需要建立一个指向链表L的结点,然后沿着链表L逐个向后搜索即可,代码如下:

//便利输出单链表void printList(LinkedList L){Node *p=L->next;int i=0;while§{printf(“第%d个元素的值为:%d\n”,++i,p->data); p=p->next; }}

对于元素修改操作,以下是代码实现:

//链表内容的修改,在链表中修改值为x的元素变为为k。LinkedList LinkedListReplace(LinkedList L,int x,int k){Node *p=L->next;int i=0;while§{if(p->data==x){ p->data=k; } p=p->next; }return L;}

简单的遍历设计的函数只需要void无参即可,而当涉及到元素操作时,可以设计一个LinkedList类型的函数,使其返回一个操作后的新链表。

插入操作

链表的插入操作主要分为查找到第i个位置,将该位置的next指针修改为指向我们新插入的结点,而新插入的结点next指针指向我们i+1个位置的结点。

其操作方式可以设置一个前驱结点,利用循环找到第i个位置,再进行插入。

如图,在DATA1和DATA2数据结点之中插入一个NEW_DATA数据结点:

从原来的链表状态:

img

到新的链表状态:

img

代码实现如下:

//单链表的插入,在链表的第i个位置插入x的元素LinkedList LinkedListInsert(LinkedList L,int i,int x){Node *pre; //pre为前驱结点 pre = L;int tempi = 0;for (tempi = 1; tempi < i; tempi++) { pre = pre->next; //查找第i个位置的前驱结点 } Node *p; //插入的结点为p p = (Node *)malloc(sizeof(Node)); p->data = x; p->next = pre->next; pre->next = p;return L;}
删除操作

删除元素要建立一个前驱结点和一个当前结点,当找到了我们需要删除的数据时,直接使用前驱结点跳过要删除的结点指向要删除结点的后一个结点,再将原有的结点通过free函数释放掉。如图所示:

img

代码如下:

//单链表的删除,在链表中删除值为x的元素LinkedList LinkedListDelete(LinkedList L,int x) {Node *p,*pre; //pre为前驱结点,p为查找的结点。 p = L->next;while(p->data != x) { //查找值为x的元素 pre = p; p = p->next; } pre->next = p->next; //删除操作,将其前驱next指向其后继。 free§;return L;}

基本操作代码

package com.ma.linked;

public class DLLinkedList {
   //定义一个头节点
    private GoodsNode head = new GoodsNode(0,"",0);


    //往链表中添加结点
    public void add(GoodsNode node){
        GoodsNode temp = head;
        while (true){
            if(temp.next == null){
                break;
            }
            temp = temp.next;
        }
        temp.next = node;
    }


    //根据商品的id值进行添加,从小到大依次排序
    public void addOrder(GoodsNode node){
        GoodsNode temp = head;
        boolean flag = false;
        while (true){
            if(temp.next == null){
                break;
            }
            if (temp.next.id >node.id ){
                break;
            }else if (temp.next.id == node.id){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            System.out.println("已经存在了此商品,请勿重复添加");
        }else {
            node.next = temp.next;
            temp.next = node;
        }
    }


    /*
    * 修改结点
    * 1.先找到链表中目标结点
    * 2.根据新数据进行修改
    * 3.根据商品编号进行查找
    * */
    public void updateNode(GoodsNode node){
        //如果链表为空
        if (head.next == null){
            System.out.println("链表为空");
            return;
        }

        GoodsNode temp = head.next;
        boolean flag = false;
        while (true){
            if (temp == null){
                break;
            }
            if (temp.id == node.id){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            //真正的修改结点
            temp.name = node.name;
            temp.price = node.price;
        }else {
            System.out.println("你要修改的结点在链表中未找到");
        }
    }


    //结点删除功能
    public void delNode(int id){
        GoodsNode temp = head;
        boolean flag = false;
        while (true){
            if (temp.next == null){
                break;
            }
            if (temp.next.id == id){
                flag = true;
                break;
            }
            temp =  temp.next;
        }
        if (flag){
            temp.next = temp.next.next;
        }else {
            System.out.println("没有找到要删除的结点" );
        }
    }


    //查看链表中每一个结点元素
    public void list(){
        if (head.next == null){
            return;
        }
        GoodsNode temp = head.next;
        while (true){
            if (temp ==  null){
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }
    }}

package com.ma.linked;

public class GoodsNode {
    public int id;
    public String name;
    public double price;
    public GoodsNode next;

    public GoodsNode(int id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "GoodsNode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

演示代码

package com.ma.linked;

public class LinkedTest {
    public static void main(String[] args) {
        GoodsNode goodsNode1 = new GoodsNode(1,"耐克鞋子",999.9);
        GoodsNode goodsNode2 = new GoodsNode(2,"阿迪鞋子",777.9);
        GoodsNode goodsNode3 = new GoodsNode(3,"李宁鞋子",555.9);
        GoodsNode goodsNode4 = new GoodsNode(4,"安踏鞋子",222.9);
        DLLinkedList dlLinkedList = new DLLinkedList();
//        dlLinkedList.add(goodsNode1);
//        dlLinkedList.add(goodsNode2);
//        dlLinkedList.add(goodsNode3);
//        dlLinkedList.add(goodsNode4);
        dlLinkedList.addOrder(goodsNode2);
        dlLinkedList.addOrder(goodsNode4);
        dlLinkedList.addOrder(goodsNode1);
        dlLinkedList.addOrder(goodsNode3);

        dlLinkedList.add(new GoodsNode(8,"特步鞋子",333.9));
        dlLinkedList.addOrder(new GoodsNode(5,"鸿星尔克鞋子",111.9));
        dlLinkedList.updateNode(new GoodsNode(8,"特步鞋子",444.9));
        dlLinkedList.delNode(8);
        dlLinkedList.list();



    }
}

);

    dlLinkedList.add(new GoodsNode(8,"特步鞋子",333.9));
    dlLinkedList.addOrder(new GoodsNode(5,"鸿星尔克鞋子",111.9));
    dlLinkedList.updateNode(new GoodsNode(8,"特步鞋子",444.9));
    dlLinkedList.delNode(8);
    dlLinkedList.list();



}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值