算法与数据机构入门经典(链表)

    今天可能着重在双向链表、栈、队列的一些学习,入门级别的学习。

1.链表概念

      链表是非连续、非顺序、的链式存储结构。由一些列节点组成,他们的逻辑顺序是通过链表中的指针链接顺序表示的。结点包括两部分,数据域与指针域,数据域用来存储相应的数据,指针域用来存储链表结点的逻辑关系。

                       

2.双向链表


   双向链表每个节点中有两个指针域,pre指针和next指针,pre指针指向该节点的前驱节点,其中特殊的是,表头节点的pre指针指向表尾节点;next指针指向该节点的后继节点。

  链表一般分为带头节点和不带头节点的链表,带头节点链表更容易实现添加删除遍历节点操作,减少对第一个数据节点的特殊处理。

                              

3.双向链表的遍历

     3.1创建5个节点

                                         

   3.2通过pre指针 和 next指针 将他们连接 在一起:

              

     3.3 遍历他们,并打印节点的值:

           

      代码实现:

#include <stdio.h>
typedef struct ListNode ListNode;
struct ListNode {
	int data;
	ListNode *pre;
	ListNode *next;
};

//向前打印
void print_next(ListNode *root) {
	ListNode *p = root;
	printf("List value is:");
	while (p) {
		printf("[%d]", p->data);
		p =p->next; //后驱节点地址的 指针域
	}
	printf("\n");
}

//向后打印
void print_pre(ListNode *root) {
	ListNode *p = root;
	printf("List value is:");
	while (p) {
		printf("[%d]", p->data);
		p = p->pre;//前驱节点地址的 指针域
	}
	printf("\n");
}

int main() {
	ListNode a;
	ListNode b;
	ListNode c;
	ListNode d;
	ListNode e;
	
	//初始化节点
	a.data = 1;
	a.pre = NULL;
	a.next = NULL;
	b.data = 2;
	b.pre = NULL;
	b.next = NULL;
	c.data = 3;
	c.pre = NULL;
	c.next = NULL;
	d.data = 4;
	d.pre = NULL;
	d.next = NULL;
	e.data = 5;
	e.pre = NULL;
	e.next = NULL;
	
	// 链接节点
	a.next = &b;
	b.pre = &a;
	b.next = &c;
	c.pre = &b;
	c.next = &d;
	d.pre = &c;
	d.next = &e;
	e.pre = &d;

	//打印
	print_next(&a);
	print_pre(&d);
	getchar();
	return 0;
}
结果如下:

                                          

前面画横线,实际上是用于填空,大家可以自己先谢谢。

4.双向链表的节点插入

                   

                         

我记得书上说a,b顺序不能颠倒,否则会出错。

代码:

          

5.双向链表的删除操作

    

 1.建立待删除节点 前后两节点的连接关系

   a、使待删除节点的前节点next指针指向待删除节点的后节点

    b、使待删除节点的后节点的pre指针指向待删除节点的前节点

  2、释放删除节点

      注意:上面的黑色实线箭头可以不用管理的,进行上面的操作后,黑色实线会自动断掉,这个是我在书上看到的,如果觉得错了的朋友欢迎留言指正。 (我前面那句话错了,准备描述是黑实线在free函数后就自动断了)

 代码:

                           

6.双向链表的基本操作测试代码

    

#include<stdio.h>
#include<malloc.h>

typedef struct ListNode ListNode;

struct ListNode{
	int data;
	ListNode *pre;
	ListNode *next;
};

void list_insert(ListNode *pre_node, int data){
	ListNode *next_node = pre_node->next;			
	ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
	new_node->data = data;
	new_node->pre= pre_node;
	new_node->next = next_node;	
	pre_node->next = new_node;
	if(next_node){
        next_node->pre = new_node;
    }
}


void list_delete(ListNode * delete_node){
	if(delete_node->pre){
		delete_node->pre->next = delete_node->next;
	}
	if(delete_node->next){
		delete_node->next->pre = delete_node->pre;
	}
	free(delete_node);
}

void print(ListNode *root){
	ListNode *p = root;
	printf("List value is: ");
	while(p){
		printf("[%d] ", p->data);
        p = p->next;
	}
	printf("\n");
}

int main(){
	ListNode a;
	ListNode b;
	ListNode c;
	a.data = 1;
	a.pre = NULL;
	a.next = NULL;
	b.data = 2;
	b.pre = NULL;
	b.next = NULL;
	c.data = 3;
	c.pre = NULL;
	c.next = NULL;
	a.next = &b;
	b.pre = &a;
	b.next = &c;
	c.pre = &b;
	print(&a);
	list_insert(&a, 999);
	print(&a);
	list_insert(&b, 888);
	print(&a);
	list_insert(&c, 777);
	print(&a);
	list_delete(a.next);
	print(&a);
    return 0;
}

结果:

                                    

之前运行这段代码的时候出错了,如下图:

 

      野指针呀!!!,原因就是:下面的代码写错了。更正后好啦,所以会debug很重要很重要!!!会改代码的第一条就是会debug,这个是技能呀,影响着正常发挥。

                            

上分代码只能删除 添加的节点,因为对于

        ListNode a;
	ListNode b;
	ListNode c;
这三个节点是不能free的,而动态分配出来的节点是可以free的。所以上份代码只能用于删除动态分配的节点。

链表结构直接使用不多,有链表基础知识后,通过链表构造更加复杂的数据结构,如:队列,栈,堆,二叉树,图等数据结构。

猜你喜欢

转载自blog.csdn.net/qq_37791134/article/details/80866129