c语言实现单链表的一般操作(王道课后题)

      手动实现了王道辅导书上单链表的部分习题,包含了各种各样对单链表的简单操作,包括但不限于建立链表,插入元素,删除,查找,输出,翻转,排序,分裂,合并,公共结点, 极值等等,未来还会继续更新,本来是对java和c的格式有些混淆了的,但是一段时间不写java,只写c语言,对c的格式就很清晰了  D:

#include
#include 
#define  ElemType int

//定义单链表
typedef struct LNode {
	ElemType data;
	struct LNode* next;
	//仅设置了前驱节点,没有写建立方法
	struct LNode* prior;
}LNode, * LinkedList;

//头插法建立带头节点的单链表 建立链表的时候要用&表示引用传参,形参改变的同时随参也变化
LinkedList List_HeadInsert(LinkedList& L) {
	LNode* s;
	int x;
	L = (LinkedList)malloc(sizeof(LNode));
	L->next = NULL;
	scanf("%d", &x);
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		scanf("%d", &x);
	}

	return L;
}
//尾插法建立单链表 
LinkedList List_TailInsert(LinkedList& L) {
	//尾插法就要设置尾指针
	L = (LinkedList)malloc(sizeof(LNode));
	LNode* s, * r = L;
	int x;
	scanf("%d", &x);
	while (x != 9999) {
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}

//试编写算法将带头结点的单链表就地逆置(就地是指辅助空间复杂度为O(1))[头插法]
LinkedList Reserve1(LinkedList& L) {
	LNode* p = L->next, * r;
	L->next = NULL;
	while (p != NULL) {
		r = p->next;
		p->next = L->next;
		L->next = p;

		p = r;
	}
	return L;
}
//试编写算法将带头结点的单链表就地逆置(就地是指辅助空间复杂度为O(1))[翻转法]
LinkedList Reserve2(LinkedList& L) {
	LNode* pre, * p = L->next, * r = p->next;
	p->next = NULL;
	while (r != NULL) {
		pre = p;
		p = p->next;
		r = r->next;
		p->next = pre;
	}
	L->next = p;

	return L;
}

//使带头结点的单链表L其元素递增有序
void Sort(LinkedList& L) {
	LNode* p = L->next, * pre;
	//r保持*p后继结点指针,以保证不断链
	LNode* r = p->next;
	p->next = NULL;
	p = r;
	while (p != NULL) {
		r = p->next;
		//每次循环都要置pre为L
		pre = L;
		//插入排序的典型操作,这个是从前往后寻找应该插入的点
		while (pre->next != NULL && pre->next->data < p->data) {
			pre = pre->next;
		}

		p->next = pre->next;
		pre->next = p;
		p = r;

	}

}

/*设计算法判断带头结点的循环单链表是否对称
  int Symmetry(DLinkedList L){
     DNode *p=L->next,*q=L->prior;
	 这里的q->next!=p 
	 while(p!=q&&q->next!=p){
	       if(p->data==q->data){
		       p=p->next;
			   q=q->prior;
		   }
		   else return 0;
	 }
	 return 1;
  }
*/

/*两个循环单链表,链表头指针分别为L1和L2,编写函数将链表L2链接到L1后,要求链接后的链表
  仍然是循环链表
*/
LinkedList Link(LinkedList& L1, LinkedList& L2) {
	LNode* p, * q; 
	p = L1;
	while (p->next != L1) {
		p = p->next;
	}
	q = L2;
	while (q->next != L2) {
		q = q->next;
	}
	p->next = L2;
	q->next = L1;
	return L1;
}



//按序号查找结点值
LNode* GetElem(LinkedList L, int i) {
	int j = 1;
	LNode* p = L->next;
	if (i == 0) return L;
	if (i < 1) return NULL;
	while (p != NULL && j < i) {
		p = p->next;
		j++;
	}
	return p;
}
//按值查找表结点
LNode* LocateElem(LinkedList L, ElemType e) {
	LNode* p = L->next;
	while (p != NULL && p->data != e)
	{
		p = p->next;
	}
	return p;
}


//求单链表的长度
int Length(LinkedList L) {
	int i = 1;
	if (L->next == NULL) {
		return 0;
	}
	else {
		LNode* p = L->next;
		while (p->next != NULL) {
			p = p->next;
			i++;
		}
	}

	return i;
}

//给定两个单链表,编写算法找出两个链表的公共结点(是公共结点,不是数据域相同的点)
//这道题两个链表构成一个Y字型,其实没有什么意义
LinkedList Search_1st_Common(LinkedList L1, LinkedList L2) {
	int len1 = Length(L1), len2 = Length(L2);
	int dist = 0;
	LinkedList longList, shortList;
	if (len1 > len2) {
		longList = L1->next;
		shortList = L2->next;
		//表长值差
		 dist = len1 - len2;
	}
	else {
		longList = L2->next;
		shortList = L1->next;
		 dist = len2 - len1;
	}
	while (dist--) {
		longList = longList->next;
	}
	while (longList != NULL) {
		if (longList == shortList) {
			return longList;
		}
		else {
			longList = longList->next;
			shortList = shortList->next;
		}
	}
	return NULL;

}

/*将一个带头结点的单链表A分解为两个带头结点的单链表A和B,使得A表中含有原表中序号为
  奇数的元素,B表中含有原表中序号为偶数的元素,且保持其相对顺序不变
 (灵活使用头插法和尾插法,改变链表的首尾顺序)
*/

LinkedList DisCreat_1(LinkedList& A) {
	int i = 0;
	LinkedList B = (LinkedList)malloc(sizeof(LNode));
	B->next = NULL;
	LNode* ra=A, * rb=B;

	LNode* p = A->next;
	A->next = NULL;
	while (p != NULL) {
		i++;
		if (i % 2 == 0) {
			rb->next = p;
			rb = p;
		}
		else {
			ra->next = p;
			ra = p;
		}
		p = p->next;
	}
	ra->next = NULL;
	rb->next = NULL;
	return B;

}

/*
  A,B是两个带头结点的单链表,元素都递增有序,设计算法从A和B中公共元素产生单链表C
  并且不破坏A,B结点
*/

LinkedList GetCommon(LinkedList La,LinkedList Lb) {
	LinkedList Lc = (LinkedList)malloc(sizeof(LNode));
	LNode* r = Lc;
	LNode* pa = La->next, * pb = Lb->next;
	while (pa && pb) {
		if (pa->data < pb->data) {
			pa = pa->next;
		}
		else if (pa->data > pb->data) {
			pb = pb->next;
		}
		else {
			LNode* s = (LNode*)malloc(sizeof(LNode));
			s->data = pa->data;
			r->next = s;
			r = s;
			pa = pa->next;
			pb = pb->next;
		}

	}
	r->next = NULL;
	return Lc;
}

/* 
  两个链表A和B分别表示两个集合,按元素递增排列,
  编制函数,求A与B的交集并存放在A链表中  (上一个方法的提升版)
*/

LinkedList Union(LinkedList &La,LinkedList &Lb) {
	LNode* pa = La->next, * pb = Lb->next;
	LNode* r = La, * q;
	while (pa && pb) {
		if (pa->data < pb->data) {
			q = pa;
			pa = pa->next;
			free(q);
		}
		else if (pa->data > pb->data){
			q = pb;
			pb = pb->next;
			free(q);
			}
		else {
			r->next = pa;
			r = pa;
			pa = pa->next;

			q = pb;
			pb = pb->next;
			free(q);
		}
		r->next = NULL;
	}
	if (pa) {
		pb = pa;
	}
	while (pb) {
		q = pb;
		pb = pb->next;
		free(q);
	}
	free(Lb);
	return La;
}

/*
  两个整数序列A=a1,a2,a3...am和B=b1,b2,b3...bm已经存入两个单链表中,设计算法
  判断序列B是否是序列A的子序列
  (暴力匹配)
*/

int Pattern(LinkedList La, LinkedList Lb) {
	//假定A和B都没有头结点
	LNode* p = La;
	LNode* pre = p;
	LNode* q = Lb;
	while (p && q) {
		if (p->data == q->data) {
			p = p->next;
			q = q->next;
		}
		else {
			pre = pre->next;
			p = pre;
			q = Lb;
		}
	}
	if (q == NULL) return 1;
	else return 0;
}



/*假设有两个按元素值递增次序排列的单链表,将这两个单链表归并为一个按元素值递减次序
  排列的单链表,并要求用原来两个单链表的结点存放归并后的单链表

  在合并的时候就可以运用头插法或者尾插法来使新链表减序或者增序
*/
void MergeList(LinkedList &La,LinkedList &Lb) {
	LNode* r, * pa = La->next, * pb = Lb->next;
	La->next = NULL;

	while (pa && pb) {
		if (pa->data <= pb->data) {
			r = pa->next;
			pa->next = La->next;
			La->next = pa;
			pa = r;
		}
		else {
			r = pb->next;
			pb->next = La->next;
			La->next = pb;
			pb = r;
		}
	}
		//这个很巧妙,不管哪个链表剩下了,都可以用下面一个代码表示
		if (pa) {
			pb = pa;
		}
		while (pb) {
			r = pb->next;
			pb->next = La->next;
			La->next = pb;
			pb = r;
		}
		free(Lb);
}



//插入结点操作,在第i个节点的之前插入e
//如果是在第i个节点之后插入,就将 GetElem(L, i-1);中的i-1改为i
LinkedList List_Insert(LinkedList& L, int i, ElemType e) {
	if (i <= 0) {
		return NULL;
	}
	LNode* s = new LNode;
	s->next = NULL;
	s->data = e;

	LNode* p = GetElem(L, i - 1);
	s->next = p->next;
	p->next = s;

	return L;
}
//删除节点操作
LinkedList List_Delete(LinkedList& L, int i) {
	if (i <= 0) {
		return	NULL;
	}

	LNode* p = GetElem(L, i - 1);
	LNode* q = p->next;
	p->next = q->next;
	free(q);

	return L;
}

//设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
void Delete_x_WithoutHead(LinkedList& L, ElemType x) {
	//p指向待删除的结点
	LNode* p;
	if (L == NULL) {
		return;
	}
	if (L->data == x) {
		p = L;
		L = L->next;
		//因L为引用,在原链表中进行操作 free 不会断链
		free(p);
		Delete_x_WithoutHead(L, x);
	}
	else {
		Delete_x_WithoutHead(L->next, x);
	}
}

//在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,
//假设值为x的结点不唯一,试编写算法实现
void  Delete_x_WithHead(LinkedList& L, ElemType x) {
	if (L->next == NULL) {
		return;
	}
	//设置三个结点,q永远指向被删除结点,pre是p的前驱结点
	LNode* p = L->next, * pre = L, * q;
	while (p != NULL) {
		if (p->data == x) {
			q = p;
			p = p->next;
			pre->next = p;
			free(q);
		}
		else {
			pre = p;
			p = p->next;
		}
	}
}

//在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值唯一)
void Delete_Min(LinkedList& L) {
	LNode* p = L->next, * pre = L, * minp = p, * minpre = pre;
	//ElemType min = p->data;
	while (p != NULL) {
		if (p->data < minp->data) {
			minp = p;
			minpre = pre;
		}
		pre = p;
		p = p->next;
	}
	minpre->next = minp->next;
	free(minp);
}

//有头结点的单链表所有元素结点的值无序,删除表中所有介于给定的两个值(作为函数参数给出)
//之间的元素(若存在)
void Delete_Range(LinkedList& L, int min, int max) {
	LNode* p = L->next, * pre = L;
	while (p != NULL) {
		if (p->data > min && p->data < max) {
			pre->next = p->next;
			free(p);
			p = pre->next;
		}
		else {
			pre = p;
			p = p->next;
		}
	}
}

//在一个递增有序单链表中,设计算法去掉数值相同的元素
//()
void Delete_SameElem(LinkedList &L) {
	LNode* p = L->next, * q;
	if (p == NULL) {
		return;
	}

	while (p->next!= NULL) {
		q = p->next;
		if (p->data == q->data) {
			p->next = q->next;
			free(q);
		}
		else {
			p = p->next;
		}
	 }
}

//输出单链表的值
LinkedList Print_List(LinkedList  L) {
	LNode* p = L->next;
	while (p != NULL) {
		printf("%d\n", p->data);
		p = p->next;
	}
	return L;
}

//L为带头结点的单链表,从尾到头反向输出每个结点的值
void Print_R(LinkedList L) {
	if (L->next != NULL) {
		Print_R(L->next);
	}
	if (L->data != NULL) {
		printf("%d",L->data);
	}
}

//带头结点单链表,按递增次序输出单链表中各结点的数据元素,并释放结点所占的存储空间
//(不使用数组作为辅助空间),遍历链表,找到最小值元素,释放之,再找次小元素,周而复始至链表为空
//最后释放头结点
void Print_Up1(LinkedList& L) {
	LNode* p, * pre, * q;
	while (L->next != NULL) {
		pre = L;
		p = pre->next;
		while (p->next != NULL) {
			if (p->next->data < pre->next->data) {
				pre = p;
			}
			p = p->next;
		}
		printf("%d", pre->next->data);
		q = pre->next;
		pre->next = q->next;
		free(q);
	}
	free(L);
}

//带头结点单链表,按递增次序输出单链表中各结点的数据元素,并释放结点所占的存储空间
//(不使用数组作为辅助空间),遍历链表,找到最小值元素,释放之,再找次小元素,周而复始至链表为空
//最后释放头结点,感觉Print_Up1在找到最小结点的过程中有些混乱且低效,故有Print_Up2
void Print_Up2(LinkedList& L) {
	LNode* p, * pre, * minp, * minpre;
	while (L->next != NULL) {
		p = L->next;
		pre = L;
		minp = p;
		minpre = pre;
		ElemType min = p->data;
		while (p != NULL) {
			if (p->data < minp->data) {
				min = p->data;
				minp = p;
				minpre = pre;
			}
			pre = p;
			p = p->next;
		}
		printf("%d", min);
		minpre->next = minp->next;
		free(minp);
	}
	free(L);
	
}

 

你可能感兴趣的:(算法)