【数据结构学习】单链表的创建、尾插元素、指定位置插入元素、获取指定位置元素

单链表

链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

“结点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构。

链接存储方法

链接方式存储的线性表简称为链表(Linked List)。

链表的具体存储表示为:

① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)

② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))

链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。

结点结构

data域--存放结点值的数据域

next域--存放结点的直接后继的地址(位置)的指针域(链域)

链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,每个结点只有一个链域的链表称为单链表(Single Linked List)

头指针head和终端结点

单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。链表由头指针唯一确定,单链表可以用头指针的名字来命名。

终端结点无后继,故终端结点的指针域为空,即NULL。

上代码

头文件定义

#ifndef __FY_LINKLIST_H
#define __FY_LINKLIST_H

//数据类型定义
typedef int data_t;

//结点结构体定义
typedef struct node{
    data_t data;
    struct node *next;
}listnode,*linklist;

//创建一个表
linklist list_creat(void);
//表尾插入一个元素
int list_tail_insert(linklist H,data_t data);
//获取表中某个结点
listnode* list_get(linklist H,int pos);
//在指定位置插入一个元素
int list_insert(linklist H,data_t data,int post);
//遍历表
int list_show(linklist H);

#endif

 C文件

#include "linklist.h"
#include "stdio.h"
#include "stdlib.h"

//创建一个结点
listnode *creatNode(data_t data){
    listnode *newnode = (listnode *)malloc(sizeof(listnode));
    if(newnode==NULL){
        printf("创建结点失败!\n");
        return NULL;
    }
    newnode->data = data;
    newnode->next = NULL;
    return newnode;
}

//创建一个表
linklist list_creat(void){
    linklist H = (linklist)malloc(sizeof(listnode));
    if(H==NULL){
        printf("创建链表失败!\n");
        return NULL;
    }
    H->data = 0;
    H->next = NULL;
    return H;
}

//表尾插入一个元素
int list_tail_insert(linklist H,data_t data){
    if(H == NULL) {
        printf("链表不存在!\n");
        return -1;
    }
    listnode *newnode = creatNode(data);
    if(newnode == NULL) return -1;
    listnode *p = H;

    while(p->next != NULL){
        p = p->next;
    }
    p->next = newnode;
    return 0;
}

//获取表中某个结点的地址
/*
定义:
头结点的位置是-1
结点的位置是从0开始的,
*/
listnode * list_get(linklist H,int pos){
    int i;
    listnode *p;
    //防御性编程
    if(H==NULL){
        printf("链表不存在!\n");
        return NULL;
    }
    if(pos<-1) {
        printf("获取节点失败,位置无效!\n");
        return NULL;
    }
    if(H->next == NULL){
        printf("获取结点失败,链表为空!\n");
    }

    p = H;//指向头结点,位置为-1
    for(i=-1;i<pos;i++){
        if(p->next == NULL){
            printf("获取结点失败,结点位置不存在!\n");
            return NULL;
        }
        p = p->next;
    }
    return p;
}

//在指定位置插入一个元素
int list_insert(linklist H,data_t data,int post){
    if(H==NULL){
        printf("插入结点失败,链表不存在!\n");
        return -1;
    }
    //获取结点位置的上一个结点
    listnode *lastnode = list_get(H,post-1);
    if(lastnode == NULL) {
        printf("插入结点失败,位置不合法!\n");
        return -1;
    }
    //为该元素创建一个结点
    listnode *newnode = creatNode(data);
    newnode->next = lastnode->next;
    lastnode->next = newnode;
    return 0;
}

//遍历表
int list_show(linklist H){
    if(H == NULL){
        printf("遍历链表失败,链表不存在!\n");
        return -1;
    }
    listnode *p = H;
    while(p->next !=NULL){
        p = p->next;
        printf("%d ",p->data);
    }printf("\n");
    return 0;
}

测试的main文件

#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"


int main(void){
	data_t value;
    //创建一个空链表
    linklist H = list_creat();

	//初始化插入几个数据
    list_tail_insert(H,1);
    list_tail_insert(H,3);
    list_tail_insert(H,5);
    list_tail_insert(H,7);
	printf("初始链表数据为:\n");
	list_show(H);
	printf("\n***********尾插法插入元素测试***********\n");
	while(1){
		printf("请输入一个数据,输入-1为结束测试!\n");
		scanf("%d",&value);
		if(value == -1) break;
		list_tail_insert(H,value);
		printf("插入新数据后的链表元素为:\n");
		list_show(H);
	}
	printf("\n***********查找指定位置元素测试**********\n");
	while(1){
		printf("请输入一个位置,输入-1为结束测试!\n");
		scanf("%d",&value);
		if(value == -1) break;
		listnode *p = list_get(H,value);
		if(p!=NULL){
			printf("该位置的元素数据为:%d\n",p->data);
		}
	}
	printf("\n***********指定位置插入元素测试**********\n");
	while(1){
		int pos;
		data_t data;
		int res;
		printf("请输入要插入的位置及要插入的数据:如2 3代表在第二个位置插入数据3\n输入-1 -1为结束测试!\n");
		scanf("%d %d",&pos,&data);
		if(pos == -1 && data == -1) break;
		res = list_insert(H,data,pos);
		if(res == 0){
			printf("在指定位置插入元素成功,插入后的链表为:\n");
			list_show(H);
		}
	}
    list_show(H);

    return 0;
}

 测试运行结果如下:

By Urien 2021年2月2日 23:03:57

 

 

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据结构与算法 排序算法 内排序 八大基础排序 选择排序 简选择排序 思想 每次选择最大的数插入到末中 做法 外层for循环控制次数 内层for循环找出最大的值的角标 找出最大角标后,进行交换 优化思路 同时获取最大值和最小值,然后分别插入数组的首部和部 堆排序 思想 使用大顶堆的思想来排序,每次建堆后交换 做法 总体:建堆-替换 建堆 只要左子树或右子树大于当前根节点,则替换 替换后会导致下面的子树发生了变化,因此同样需要进行比较,直至各个节点实现父>子这么一个条件(递归) 交换排序 冒泡排序 思想 每次俩俩交换,将最大值交换到末 做法 外层for控制循环次数 内层for控制比较次数 每次循环之后,比较次数都会减少一次 优化思路 如果一趟排序后没有发生位置变化,那么此时就是有序了 快速排序 思想 每次将比支点小的放在支点左边,比支点大的放在支点右边 做法 外循环while只要i和j不碰撞查找 内层两个while循环分别查找出比支点小的和比支点大的角标 如果i<=j满足条件,就交换 一趟排序后,支点的左边都比支点小,支点右边都比支点大 只要满足L<j,i0的条件查找出要插入的何时位置 退出内层while循环后就找到了合适的位置插入 优化思路 二分查找插入,找合适位置的时候使用二分查找算法 希尔排序 思想 用增量来将数组进行分隔,直到增量为1。底层干的还是插入排序干的活 做法 最外层for外循环控制增量的数量,每次/2 第二层for循环控制每次增量那组开始进行插入排序,直至完毕 第三层while循环找到要插入到哪个位置 归并排序 思想 将两个已排好序的数组合并成一个有序的数组 做法 递归拆分出两个有序的数组,从mid的位置开始拆分,递归出口:只有一个值的时候就不用拆分了 合并两个有序的数据 分别往两个数组填充已有序的数据 比较两个数组的值谁小,谁小就放到我们的数组中 如果比较完之后还有剩余的数据,那么用while直接添加到我们的总数组中 优化思路 当递归到规模足够小时,利用插入排序 归并前判断一下是否还有必要归并 只在排序前开辟一次空间 基数(桶)排序 思想 分配,回收(分配到不同的位置上,然后回收)..不断分配..回收来进行排序,直到有序 做法 分配一个[array.length][10列]的二维数组来装我们的元素 最外层for循环控制要分配和回收的次数(根据最大值) 将元素的个、十、百位依次放到桶子上(第一次就是放个位,第二次放十位) 依据每列回收桶子,两个for循环 外排序 查找算法 二分查找 分块查找 哈希查找 贪心算法 求最小生成树的Prim算法和Kruskal算法 爬山问题 回溯算法 n皇后问题 动态规划Dynamic Planning 应用 求最长公共子序列LCS 矩阵连乘问题 爬楼梯问题 找零问题 0-1背包问题 分治算法Divide and Conquer 应用:归并排序 其它 Rabin fingerprints 文件指纹算法 BitMap 位图算法 BloomFilter 布隆过

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值