单链表



链表Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

链表有很多种不同的类型:单向链表,双向链表以及循环链表(以上参考维基百科)

本章主要讲解单向链表

1、插入

下面是链表的按序插入过程(以结点中key值的大小作为插入依据,递增排序)。

其实现的过程考虑三种情况:

1)L为空;

2)在链表的头部插入;

3)在链表的中间插入(包括在链表尾部插入的情况)。

 单链表_第1张图片

2、删除

删除和插入是一个相反的过程,一般需要先找的删除结点的前驱(prev

1)删除链表的首结点(prev == NULL);

  L = cur->next

2)删除链表的中间结点。

  prev->next = cur->next

3、反转

对单链表进行反转操作,图(2)、(3)为反转的过程。

 

4、合并

将两个已排序的链表进行合并

 

/********************************************************
 * 简单的单链表(无哑结点) 
 *******************************************************/

#include <stdio.h>
#include <stdlib.h>

typedef struct lnode {
	int key;
	struct lnode *next;
} LNode, *LIST;

//=============================================================
// 根据key值,获得该节点位置
//=============================================================
static inline LNode *ListSearch(LIST l, int key)
{
	LNode *p = l;

	while (p && p->key != key)
		p = p->next;

	return p;
}

//=============================================================
// 获取x结点的前驱
//=============================================================
static inline LNode *GetPrev(LIST l, LNode *x)
{
	LNode *prev = l;

	while (prev && prev->next != x)
		prev = prev->next;

	return prev;
}

//=============================================================
// 按序插入结点
//=============================================================
LNode *ListInsert(LIST l, LNode *x)
{
	if (l == NULL) // case 1
		return x;
	
	if (x->key < l->key) { // case 2
		x->next = l;
		l = x;
	} else {               // case 3
		// 获得x的前驱
		LNode *prev = l;   
		while (prev->next && prev->next->key <= x->key)
			prev = prev->next;
		x->next = prev->next;
		prev->next = x;
	}

	return l;
}

//=============================================================
// 删除结点,给出待删除结点的位置(指针)
//=============================================================
LIST ListDelete(LIST l, LNode *x)
{
	if (l == NULL)
		return NULL;

	if (l == x) { // case 1 /*l->key == x->key*/
		l = x->next;
	} else {      // case 2
		// 获得x的前驱
		LNode *prev = l;
		while (prev->next && prev->next != x) // prev->next->key < x->key
			prev = prev->next;
		prev->next = x->next;
	}

	return l;
}

//=============================================================
// 对指定的链表进行反转
//=============================================================
LIST ListReverse(LIST l)
{
	LNode *cur = l; // 当前结点
	LNode *prev = NULL; 
	LNode *next = NULL; 

	while (cur)
	{
		next = cur->next;
		cur->next = prev; // 反转
		prev = cur; // prve和cur往前移动。
		cur = next;
	}

	return prev;
}

//=============================================================
// 合并两个链表(増序)
//=============================================================
LIST ListMerge(LIST l1, LIST l2)
{
	LNode *l = NULL;
	LNode **pos = &l;

	while (l1 && l2) {
		if (l1->key < l2->key) {
			*pos = l1;
			l1 = l1->next;
		} else {
			*pos = l2;
			l2 = l2->next;
		}
		pos = &(*pos)->next; // 注意,pos指向下一个结点的地址
	} 
	if (l1)  
		*pos = l1;
	else
		*pos = l2;

	return l;
}

//=============================================================
// 交换链表中两结点的位置
//=============================================================
LIST ListSwap(LIST l, LNode *x, LNode *y)
{
	if (l == NULL)
		return l;
	
	// 获取x、y的前驱
	LNode *xprev = GetPrev(l, x);
	LNode *yprev = GetPrev(l, y);

	LNode *xnext = x->next; // 记录
	x->next = y->next; // 相当于插入x
	if (yprev == NULL) // y为头结点
		l = x;
	else
		yprev->next = x;

	y->next = xnext;   // 相当于插入y
	if (xprev == NULL) // x为头结点
		l = y;
	else
		xprev->next = y;

// 	if (xprev == NULL) {
// 		LNode *xnext = x->next;
// 		x->next = y->next; // 相当于插入x
// 		yprev->next = x;
// 		y->next = xnext;   // 相当于插入y
// 		l = y;
// 	} else if (yprev == NULL){
// 		LNode *ynext = y->next;
// 		y->next =x->next;
// 		xprev->next = y;
// 		x->next = ynext;
// 		l = x;
// 	} else {
// 		LNode *xnext = x->next;
// 		x->next = y->next; // 相当于插入x
// 		yprev->next = x;
// 		y->next = xnext;   // 相当于插入y
// 		xprev->next = y;
// 	}

	return l;
}

//=============================================================
// 对指定的链表进行输出
//=============================================================
void ListPrint(LIST l)
{
	LNode *p = l;

	while (p) {
		printf("%d\t", p->key);
		p = p->next;
	}

	printf("\n");
}

int main()
{
	int arr[] = {34, 2, 53, 21, 354, 78};
	int len = sizeof(arr) / sizeof(arr[0]);
	LIST l1 = NULL;
	LIST l2 = NULL;
	LIST l = NULL;

	printf("Insert:\n");
	for (int i = 0; i < len; i++) {
		LNode *x = (LNode *)malloc(sizeof(LNode));
		if (!x) {
			printf("x malloc error\n");
			return -1;
		}
		x->key = arr[i];
		x->next = NULL;
		l1 = ListInsert(l1, x);
		ListPrint(l1);
		LNode *y = GetPrev(l1, ListSearch(l1, arr[i]));
		if (y == NULL)
			printf("%d is not prev!\n", arr[i]);
		else
			printf("%d prev is %d\n", arr[i], y->key);
	}

	printf("Insert:\n");
	for (int i = 0; i < len - 2; i++) {
		LNode *x = (LNode *)malloc(sizeof(LNode));
		if (!x) {
			printf("x malloc error\n");
			return -1;
		}
		x->key = arr[i] * 2 - 40;
		x->next = NULL;
		l2 = ListInsert(l2, x);
		ListPrint(l2);
	}

	printf("Merge:\n");
	l = ListMerge(l1, l2);
	ListPrint(l);
	
	printf("Delete:\n");
	l = ListDelete(l, ListSearch(l, -36));
	ListPrint(l);

	printf("Reverse:\n");
 	l = ListReverse(l);
 	ListPrint(l);

	printf("Swap():\n");
	l = ListSwap(l, ListSearch(l, arr[1]), ListSearch(l, arr[4]));
	ListPrint(l);

// 	printf("Delete:\n");
// 	for (int i = 0; i < len; i++) {
// 		l = ListDelete(l, ListSearch(l, arr[i]));
// 		ListPrint(l);
// 	}
	
	LNode *y = GetPrev(l, ListSearch(l, 53));
	printf("53 prev is %d\n", y->key);

	system("pause");
	return 0;
}



你可能感兴趣的:(单链表)