附录:对于头结点单向链表的优化方法

————————————本文旨在交流学习计算机知识,欢迎交流讨———————————

        上一章,我们浅显的讨论了链表的结构,本文在上一章的链表的基础上做出了些许优化,可配合食用。

        回到正题,我们已经了解链表的结构,它是一种非连续空间存储的线性表,主要依靠地址域访问下一个元素并通过遍历操作进行增删改查。

如图,这是我们上一章所介绍的链表结构:

我们的惯用操作:

//单向链表的插入,删除(先找到节点p):

//插入:
newnode->next=p->next;
p->next=newnode;
//删除:
node_new temp;
temp=p->next;
p->next=p->next->next;
free(temp);

看着这幅图,我们不禁想到一个问题:我们真的需要这个头节点吗,是否有些看起来不整齐且结构不一致?于是,我们考虑到:也许我们可以用指针标记header的位置,然后再在每一次的函数接口里面新建一个头结点,用完即删,这样或许看起来更加的整齐和高效。

如图所示:

这时,我们引入dummy节点,并将其放入栈,dummy节点充当第一个节点。

void insert(link*header,element val)
{
    node_t dummy;
    dummy->next=header;//header为我们的指针(因为简化了头结点,我们只传入指针)
    node_t *p=&dummy;//p为遍历指针,从dummy开始遍历;
    while(p->next)
    {
        p=p->next;
    }
    header=dummy->next;//还原操作;
}

下面,我们重写一下代码:

定义链表结构:

typedef int Element_t;
struct node{
    Element_t val;
    struct node *next;
}node_t;
//节点的结构体;

typedef struct {
	node_t *header;
	int count;
} List_t;
//链表结构体(包括头结点和数量);

 初始化链表:

void initList(List_t *table)
{
    table->count=0;
    table->header=NULL;
)

从最基础的展现函数开始:

void shouList(const List_t *table){
    node_t p=table->header;
    printf("List :");
    while(p)
    {
        printf("%d\t",p->val);
        p=p->next;
    }
    printf("\n");
}

这里如果不知道const为什么要放在形参里的可以看看我的第一篇文章,里面有详细解答。

然后就是增删改查的经典案例了:

        从增开始:

int insertListHeader(List_t* table,Element_t val)
{
node_t dummy;
dummy.next=table->header;
    
    node_t *p=&dummy;//临时头结点dummy及临时过渡中间容器p;
    node_t *new_node=malloc(sizeof(node_t));
    
    if(new_node==NULL)
    {
        printf("ERROR\n");
    )
//朴素的增加操作;
    new_node->val=val;
    new_node->next=p->next;
    p->next=new_node;
    ++table->count;
    
table->header=dummy->next;
return 0;
}

      然后这是按位插入操作:

int insertListPos(List_t* table,int pos,Element_t val)
{
    if(pos<0||pos>table->count)
    {
        printf("the pos is not a truly place\n");
    }
    node_t dummy;
    dummy.next=table->header;
    node_t* p=&dummy;
    int index=-1;//计数器;
    while(index<pos-1)
        {
            p=p->next;
            ++index;
        }//遍历查找
    node_t *new_node=malloc(sizeof(node_t));
    new_node->next=p->next;
    p->next=new_node;
    ++table->count;
    table->header=dummy.next;
    return 0;
}

        删除操作:

int deleteList(List_t* table,Element val)
{
    node_t dummy;
    dummy.next=table->header;

    node_t* p=&dummy;
    while(p->next&&p->val!=val)
        {
            p=p->next;
        }
    if(p->next==NULL)
    {
        printf("404 NOT FOUND\n");
        return 0;
    }
    node_t temp=malloc(sizeof(node_t));
    temp=p->next;
    p->next=temp->next;
    free(temp);
    --table->count;
    table->header=dummy->next;
    return 0;
}

最后的最后就是销毁链表了 :

###关于销毁链表,其原理就是按位遍历并按位删除。###

void destroyList(List_t *table) {
	node_t dummy;
	dummy.next = table->header;

	node_t *p = &dummy;
	node_t *temp;
	while (p->next) {
		temp = p->next;
		p->next = temp->next;
		free(temp);
		--table->count;
	}
	printf("LinkList have %d node!\n", table->count);
	// table->header = NULL;
}

最后,是测试函数(对比):

// 带头指针的单向链表测试
int test02() {
	List_t stu1;
	initChainList(&stu1);

	for (int i = 0; i < 10; ++i) {
		insertListHeader(&stu1, i + 100);
	}
	showList(&stu1);
	insertListPos(&stu1, 2, 220);
	showList(&stu1);

	deleteListElement(&stu1, 104);
	showList(&stu1);
	destroyList(&stu1);
	return 0;
}

int main() {
	test02();
	return 0;
}

以上就是附录内容,欢迎指正! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值