数据结构之【线性表】(顺序表、链表的基本操作实现)

概念

线性表:是N个数据元素的有限序列
顺序表:用一组地址连续的存储单元依次存储【线性表 】的数据元素。(区别于有序表:表中的数据元素存在非递增或非递减有序)
链表:用一组任意的存储单元来存储【线性表】的数据元素。
在这里插入图片描述

顺序表的声明:
0、顺序表的声明
顺序表的基本操作:
1、初始化顺序表L(InitList_Sq)
2、销毁顺序表L(DestroyList_Sq)
3、创建顺序表(Create_Sq)
4、清空顺序表(ClearList_Sq)
5、判断顺序表是否为空(ListEmpty_Sq)
6、求顺序表的长度(ListLength_Sq)
7、获取第i个数据元素的值(GetElem_Sq)
8、定位某元素e的位置(LocateElem_Sq)
9、求当前元素的直接前驱元素(PriorElem_Sq)
10、求当前元素的直接后继元素(NextElem_Sq)
11、向顺序表中插入新的元素e(ListInsert_Sq)
12、删除顺序表中第i个位置的元素(ListDelete_Sq)
13、遍历顺序表(ListTraverse_Sq)
顺序表的其他操作:
14、顺序表的就地逆置(Reverse)
15、合并顺序表(MergeList)
16、将顺序表非递减有序排序(折半插入排序)(Sort)
17、向有序表中插入元素(InsertOrderList)


(线性)链表的声明:
0、带头结点的线性链表的声明
(线性)链表的基本操作:
1、初始化顺序表L(MakeNode)
2、释放结点(FreeNode)
3、初始化链表L(InitList)
4、清空链表,并释放结点空间(DestroyList)
5、销毁链表L(ClearList)
6、在头结点后、首元结点前插入元素(InsFirst)
7、删除首元结点(DelFirst)
8、在链表尾部【追加】新的链表或结点(Append)
9、删除表尾结点(Remove)
10、在表中结点前【插入】一个新结点(InsBefore)
11、在表中结点后【插入】一个新结点(InsAfter)
12、更新某结点中数据元素的值(SetCurElem)
13、获取某结点中数据元素的值(GetCurElem)
14、判断链表是否为空(ListEmpty)
15、获取某链表的长度(ListLength)
16、返回头结点的位置(GetHead)
17、返回尾结点的位置(GetLast)
18、返回某结点的直接前驱结点的位置(PriorPos)
19、返回某结点的直接后继结点的位置(NextPos)
20、返回链表中第i个结点的位置(LocatePos)
21、返回表中与e满足compare()判定关系的元素的位置(LocateElem)
22、遍历链表(ListTraverse)
(线性)链表的其他操作:
23、逆位序创建带头结点的线性链表L(CreateList)
24、将线性链表按非递减有序排列(SortList)
25、往有序链表中插入元素e(OrderInsert)
26、合并链表(MergeList_L)
27、用【头插法】逆置单链表(ReverseList)


顺序表

------- 线性表的动态分配顺序存储结构 -------回顶部

//关键字宏定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 0
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10   //线性表存储空间的分配增量
//关键字类型说明
typedef int ElemType;
typedef int Status;
//数据元素(顺序表)的类型说明
typedef struct SqList{
	ElemType *elem; //存储空间的基地址
	int length;     //当前长度
	int listsize;   //当前分配的存储容量,以sizeof(ElemType)为单位
}SqList;

------- 顺序表的基本操作 -------

1、初始化顺序表L ----回顶部

//先分配空间,再将数组长度置为0 
Status InitList_Sq(SqList &L){ //初始化一个线性表
	L.elem=(ElemType*)malloc((LIST_INIT_SIZE)*sizeof(ElemType));
	if(!L.elem) exit(OVERFLOW);
	L.length=0;
	L.listsize=LIST_INIT_SIZE;
	return OK;
}//InitList_Sq

2、销毁顺序表L ----回顶部

void DestroyList_Sq(SqList &L){ //销毁一个线性表
	if(L.elem)
		free(L.elem);
}

3、创建顺序表 ----回顶部

//先输入线性表的长度,然后依次输入元素 
Status Create_Sq(SqList &L){ //创建一个顺序表
	printf("please input number:\n");
	scanf("%d",&L.length);	
	printf("please input keyvalue with enter:\n");
	for(int i=1;i<=L.length;i++)//subscript start from 1,方便排序  
		scanf("%d",&L.elem[i]);	
	return OK;
}

4、清空顺序表 ----回顶部

//将线性表的长度置为0 
Status  ClearList_Sq(SqList &L){
   L.length=0;
   return OK;
}

5、判断顺序表是否为空 ----回顶部

//通过判断线性表的长度来断定 
Status ListEmpty_Sq(SqList L){ //线性表判空
  if (L.length==0)
	  return TRUE;      
  else 
	  return FALSE;
}

6、求顺序表的长度 ----回顶部

int ListLength_Sq(SqList L){ //求线性表长度
   return L.length;             
}

7、获取第i个数据元素的值 ----回顶部

int GetElem_Sq(SqList L,int i,ElemType &e){ //获取表中第i个位置的元素,用e返回
	if (i<1 || i>L.length){ //取元素的位置不合法
		printf("wrong position\n");
		return ERROR;   
	}
	e=L.elem[i];//数组元素下标从1开始       
	return OK;
}

8、定位某元素e的位置 ----回顶部

Status compare(ElemType x,ElemType y){ //两个数据元素比较大小

    if(x>y)
		return 1;
    else
		if(x==y)  
			return 0;
		else
			return -1;
}
int LocateElem_Sq(SqList L,ElemType e,Status (*compare)(ElemType x,ElemType y)){ //在表中定位元素e
    int i;
    for(i=1;i<=L.length;i++){
		if(!compare(e,L.elem[i]))
			return i;
    }
    print("未找到");
    return ERROR;
}

9、求当前元素的直接前驱元素 ----回顶部

//先判断当前元素是否存在并得到其位置,然后再判断 
int PriorElem_Sq(SqList L,ElemType cur_e,ElemType &pre_e){ //求当前元素的直接前驱元素
    int i=LocateElem_Sq(L,cur_e,compare);
	if(!i){
		printf("%d isn't in the list",cur_e);
		return ERROR;
	}
	if(i==1){
		printf("%d is the first elem,it hasn't prior.\n",cur_e);
		return ERROR;
	}
	pre_e=L.elem[i-1];
	return OK;
}

10、求当前元素的直接后继元素 ----回顶部

//先判断当前元素是否存在以及所在的位置,然后再求其后继元素 
Status NextElem_Sq(SqList L,ElemType cur_e,ElemType &next_e){ //求当前元素的直接后继元素
	int i;
	if( ListEmpty_Sq(L) && (i=LocateElem_Sq(L,cur_e,compare)) ){
   		if(i!=L.length){
			next_e=L.elem[i+1];
			return OK;
		}else {
			printf("%d is the last elem,it hasn't next.\n",cur_e);
			return ERROR;
		}
	}else{
		printf("%d isn't in the list",cur_e);
		return ERROR;
	}
}

11、向顺序表中插入新的元素e ----回顶部

Status ListInsert_Sq(SqList &L,int i,ElemType e){ //将e插入到L的第i个位置之前,L长度加1

	if(i<1 || i>L.length+1){ //限制合法的插入位置
		printf("position is wrong\n");
		return ERROR;
	}
    int *p,*q;//临时指针
	int *newbase;//新的基地址
	if(L.length>=L.listsize){
		newbase=(ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
	    if (!newbase) //分配不成功
			exit(OVERFLOW);
		L.elem=newbase;
	    L.listsize+=LISTINCREMENT;
	}
	q = &(L.elem[i]);//顺序表在数组中的存储从1开始
	for(p = &(L.elem[L.length]); p>=q; --p)
	    *(p+1) = *p; //寻找插入位置,移动元素
	*(q) = e;//完成插入
	L.length++;//线性表长度增1
	return OK;
}

12、删除顺序表中第i个位置的元素 ----回顶部

//先判断要删除的位置是否合法,然后将指向此元素的指针赋给另一个变量,再将后面的元素依次向前移动一位,长度-1 
Status ListDelete_Sq(SqList &L,int i,ElemType &e){ //删除第i个位置的元素,并用e返回被删除元素
	int *p,*q;
	if( i<1 || i>L.length){
		printf("position is wrong\n");
		return ERROR;
	}
    p = &(L.elem[i]);//因为从下标1开始存数据元素,位序与下标相同
	e = *p;
	q = L.elem + L.length;
	for(++p; p<=q; ++p)
		*(p-1) = *p;
	L.length--;
	return OK;
}

13、遍历顺序表 ----回顶部

//先判断线性表是否为空,若不空,则从头开始依次遍历,此处从1开始,是因为刚开始创建线性表时就从1开始的 
void ListTraverse_Sq(SqList L){//在屏幕上输出顺序表
	int i;
	if(ListEmpty_Sq(L)){
		printf("the Sqlist is empty!\n");
		return;
	}
	for(i=1; i<=L.length; i++){ //数组下标从1开始
		printf("%d ",L.elem[i]);	
	}
	printf("\n");
}

------- 顺序表的其它操作 -------

14、顺序表的就地逆置 ----回顶部

// 算法1
//顺序表的第一个元素与最后一个元素交换,然后指针依次加1减1,重复上述活动,直到两者相遇 
void Reverse1(SqList &L){ //顺序表的就地逆置
    printf("After reve:\n");
	int temp,i,j;
    for(i=1,j=L.length; i<=j; i++,j--){
		temp=L.elem[i];
		L.elem[i]=L.elem[j];
		L.elem[j]=temp;
	}
}//reverse 
// 算法2
void Reverse2(SqList &L){ //顺序表的就地逆置 

	printf("After reve:\n");
	int temp,i;
    for(i=1;i<=(L.length)/2;i++)
	{
		temp=L.elem[i];
		L.elem[i]=L.elem[L.length+1-i];
		L.elem[L.length+1-i]=temp;
	}
}//reverse

15、合并顺序表 ----回顶部

//前提:La和Lb是非递减有序的
void MergeList(SqList La,SqList Lb,SqList &Lc){
	InitList_Sq(Lc); 
	int *pa,*pb,*pc,*pa_last,*pb_last;
	pa = &(La.elem[1]);pb = &(Lb.elem[1]); //subscript start from 1
	Lc.length = ListLength_Sq(La)+ListLength_Sq(Lb);
	Lc.listsize = ListLength_Sq(La)+ListLength_Sq(Lb);
	pc = (ElemType *)malloc(Lc.listsize*sizeof(ElemType));
	pc = &(Lc.elem[1]);//subscript start from 1
	if(!Lc.elem) exit(OVERFLOW); //存储分配失败
	pa_last = &(La.elem[La.length]);
	pb_last = &(Lb.elem[Lb.length]);
    while((pa<=pa_last) && (pb<=pb_last)){
        if(*pa <= *pb)      
			*pc++ = *pa++;
		else
			*pc++ = *pb++;
	}
    while(pa<=pa_last)
    	*pc++ = *pa++;
    while(pb<=pb_last)
		*pc++ = *pb++;
}//MergeList

16、将顺序表非递减有序排序(折半插入排序) ----回顶部

Status Sort(SqList &L){//折半插入排序
	int i,j,m,low,high;
	for(i=2;i<=L.length;++i){ 
		L.elem[0]=L.elem[i];
		low=1; high=i-1;	
		while(low<=high){     
			m=(low+high)/2;             
			if(L.elem[0]<L.elem[m]) 
				high=m-1;
			else  
				low=m+1; 
         }//while

         for(j=i-1;j>=high+1;--j)
			 L.elem[j+1] = L.elem[j];			
		 L.elem[high+1]= L.elem[0];  
     }//for
	return OK;
}  

17、向有序表中插入元素 ----回顶部

// 算法1
Status InsertOrderList1(SqList &L,ElemType x){//将x插入到递增有序的顺序表L中,插入后L仍然递增有序(算法1)
    int *p;//临时指针
	int *newbase;//新的基地址
	if(L.length >= L.listsize){
		newbase=(ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
	    if (!newbase) //分配不成功
			exit(OVERFLOW);
		L.elem=newbase;
	    L.listsize+=LISTINCREMENT;
	}
	p = &(L.elem[L.length]); //下标从1开始
	while(p>=&(L.elem[1]) && *p>x){ //寻找插入位置,移动元素
		*(p+1)=*p; 
		--p;
	}
	*(p+1) = x;//完成插入
	L.length++;//线性表长度增1
	return OK;
}
//算法2
Status InsertOrderList2(SqList &L,ElemType x){ //将x插入到递增有序的顺序表L中,插入后L仍然递增有序(算法2)

	printf("After algo2:\n");
	int *newbase;
	if(L.length >= L.listsize){
		newbase = (ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
	    if (!newbase) 
			exit(OVERFLOW);
		L.elem = newbase;
	    L.listsize += LISTINCREMENT;
	}
	int i = L.length;//数组下标从1开始
	while((i >= 1) && (x<L.elem[i]))
		i--;//i是插入位置
	int j;
	for(j=L.length; j>=i+1/*是在插入位置之后插入元素*/; j--){
		L.elem[j+1]=L.elem[j];//从第i+1到第n个元素后移
	}
	L.elem[i+1] = x;//插入
	L.length++;//长度增1
	return OK;
}
//算法3
Status InsertOrderList3(SqList &L,int x){//将x插入到递增有序的顺序表L中,插入后L仍然递增有序(算法3)
	int i;
	i=L.length;//数组下标从1开始
	while((i>=1) && (x<L.elem[i]))
		i--; //查找i是插入位置
	ListInsert_Sq(L,(i+1),x);
	return OK;
}
//算法4
Status InsertOrderList4(SqList &L,int x)//将x插入到递增有序的顺序表L中,插入后L仍然递增有序(算法4)
{
	int i;
	i=1;//数组下标从1开始
	while((i<=L.length) && (x>L.elem[i]))
		i++; //查找i是插入位置
	printf("i is  %d",i);
	ListInsert_Sq(L,i,x);//插在第i个元素之前,所以直接调用
	return OK;
}

(线性)链表

------- 线性表的【线性链表】存储结构 -------回顶部

//关键字宏定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 0
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10   //线性表存储空间的分配增量
//关键字类型说明
typedef int ElemType;
typedef int Status;
//数据元素(带头结点的线性链表)的类型说明
typedef struct LNode{ //结点类型
	ElemType data;
	struct LNode *next;
}*Link,*Position;
typedef struct{ //链表类型
	Link head,tail; //分别指向线性链表中的头结点和最后一个结点
	int len;        //指示线性链表中数据元素的个数
}LinkList;

------- 线性链表的基本操作 -------
1、构造结点-MakeNode ----回顶部

 //构造一个结点,给结点分配空间并指明数据域和指针域 
Status MakeNode(Link &p,ElemType e){
	//分配由p指向的值为e的结点,并返回OK,若分配失败,返回ERROR
	p=(Link)malloc(sizeof(LNode));
    if(p){
		p->data=e;
		p->next=NULL;
		return OK;
	}else
		return ERROR;
}//MakeNode

2、释放结点 ----回顶部

Status FreeNode(Link &p){
	//释放p所指结点
	if(p)
		free(p);
	return OK;
}

3、初始化链表L ----回顶部

Status InitList(LinkList  &L){
	//构造一个空链表L
	L.head=(Link)malloc(sizeof(LNode));
	if(L.head){
		L.head->next=NULL;
		L.tail=L.head;
		L.len=0;
		return OK;
	}
	else 
		return ERROR;
}

4、清空链表,并释放结点空间 ----回顶部

//逐步释放链表的结点,并将链表的长度每次减1,直到头尾结点相等,且长度为0 
Status ClearList(LinkList &L){
	//重置L为空表,并释放原链表的结点空间
	Link p,q;
	if(L.head!=L.tail){
		p=L.head->next;
		L.head->next=NULL;
		while(p!=L.tail){
			q=p->next;
			free(p);
			p=q;
		}
		free(p);
		L.tail=L.head;
		L.len=0;
	}
	if(L.head == L.tail )
		return OK;
	return ERROR;
}

5、销毁链表L ----回顶部

//先清空链表,然后释放头尾结点 
Status DestroyList(LinkList &L){//销毁链表,L不再存在
	ClearList(L);
	FreeNode(L.head);
	return OK;
}

6、在头结点后、首元结点前插入元素 ----回顶部

//将新节点插入到头节点的后面(若原来为空链表,则直接连接到头节点后面),并将长度加1 
Status InsFirst(LinkList &L,Link h,Link s){//已知 h指向L的头结点
	//在L的头部插入s为新首元结点
	s->next=h->next;
	h->next=s;
	if(h==L.tail)//原来是空表
		L.tail=h->next;
	L.len++;
	return OK;
}

7、删除首元结点 ----回顶部

//删除首元结点,直接将首元结点的下一个结点连接到头节点处,并释放原首元结点 
Status DelFirst(LinkList &L,Link h,Link &q){//已知 h指向L的头结点
	q = h->next;
	if(q){
		h->next = q->next;
		if(!h->next)//删除q后为空表
			L.tail = h;
		L.len--;
		free(q);
		return OK;
	}else 
		return ERROR;
}

8、在链表尾部【追加】新的链表或结点 ----回顶部

//直接将要链接的结点连接到尾结点上,并指明新的尾结点,且链表长度要改变。 
Status Append(LinkList &L,Link s){
	//将指针s所指的一串结点链接在线性链表L的最后一个结点后。
	int i = 1;
	L.tail->next = s;
	while(s->next){
		s = s->next;
		i++;
	}
	L.tail = s;//改变L的为指针指向新的尾元结点
	L.len += i;
	return OK;
}

9、删除表尾结点 ----回顶部

//先判断链表是否为空,若不空,则从头节点开始依次查找直到尾结点的前驱结点,将其指定为新对的尾结点,并删除释放原尾结点,长度-1 
Status Remove(LinkList &L,Link &q){
	//删除线性链表L中的尾结点并将q返回,改变链表L的尾指针指向新的尾节点。
	Link p;
	if(L.len == 0){
		q = NULL;
		return FALSE;
	}
	p = L.head->next;
	q = L.tail;
	while(p->next != q)
		p = p->next;
	L.tail = p;
	p->next = NULL;
	FreeNode(q);
	return OK;
}

10、在表中某结点前【插入】一个新结点 ----回顶部

//从头节点开始查找,直到要插入结点的前驱结点,然后插入 
Status InsBefore(LinkList &L,Link &p,Link s) {
	//在L中p结点前插入s,并修改指针p指向新插入的结点
	Link q;
	q = L.head;
	while(q && q->next && q->next!=p)
		q = q->next;
	s->next = q->next;
	q->next=s;
	p = s;
	L.len++;
	return OK;
}

11、在表中某结点后【插入】一个新结点 ----回顶部

//已知要插入的结点,直接在结点后面插入即可 
Status InsAfter(LinkList &L,Link &p,Link s){ 
	//在L中p结点后插入s,并修改指针p指向新插入的结点
	if(p->next){
		s->next = p->next;
		p->next = s;
	}else{
		p->next = s;
		L.tail = s; 
	}
	p = s;
	L.len++;
	return OK;
}

12、更新某结点中数据元素的值 ----回顶部

Status SetCurElem(Link p,ElemType e){
	//用e更新p所指结点的元素值。
	p->data = e;
	return OK;
}

13、获取某结点中数据元素的值 ----回顶部

ElemType GetCurElem(Link p){
	//返回p所指结点的元素值
	return p->data;
}

14、判断链表是否为空 ----回顶部

Status ListEmpty(LinkList L) {
	//若L空,返回TRUE,否则返回FALSE
	if (L.head->next == NULL) 
		return TRUE;
	else 
		return FALSE;
}

15、获取某链表的长度 ----回顶部

int ListLength(LinkList L){
	//求L的长度
	return L.len;
}

16、返回头结点的位置 ----回顶部

Position GetHead(LinkList L){
	//返回L的头结点的位置。
	return L.head;
}

17、返回尾结点的位置 ----回顶部

Position GetTail(LinkList L){
	//返回L的尾元结点的位置。
	return L.tail;
}

18、返回某结点的直接前驱结点的位置 ----回顶部

//从头节点开始查找,直到该结点的前驱结点 
Position PriorPos(LinkList L,Link p){
	//p是L的一个结点,返回p的直接前驱的位置,如果无前驱,返回NULL。
	Link q;
	q = L.head->next;
	if(q==p){
		printf("It's the first element,no prior!\n");
		return NULL;
	}
	while(q && q->next!=p)
		q = q->next;
	return q;
}

19、返回某结点的直接后继结点的位置 ----回顶部

Position NextPos(LinkList L,Link p){
	//p是L的一个结点,返回p的直接后继的位置,如果无后继,返回NULL。
	if(p->next)
		return p->next;
	else{
		printf("It's the last element,no next!\n");
		return NULL;
	}
}

20、返回链表中第i个结点的位置 ----回顶部

//先检查位置是否合法,然后从头开始查找,并计数,直到找到 
Status LocatePos(LinkList L,int i,Link &p){
	//返回L中第i个结点的位置,用p表示,i不合法时返回ERROR;
	if(i<0 || i>ListLength(L))
		return ERROR;
	int j = 1; //不算头结点,从首元结点开始 
	p = L.head->next;
	while(p && j<i){
		j++;
		p = p->next;
	}
	return OK;
}

21、返回表中与e满足compare()判定关系的元素的位置 ----回顶部

int compare(ElemType x,ElemType y)
{
    if(x>y)
		return 1;
    else
		if(x == y)  
			return 0;
		else
			return -1;
}
Position LocateELem(LinkList L,ElemType e,int(*compare)(int,int)){
	//L中第1个与e满足compare判定关系的元素的位置,若不存在这样的元素,则返回NULL。
   	LNode *p;
 	p = L.head->next;
  	while(p){
		if(!compare(e,p->data))
			return p;
		p = p->next;
  	}
  	if(!p){
		printf("the element is not exists\n");
	  	return NULL;
  	}
}

22、遍历链表 ----回顶部

//访问某结点元素
Status visit(Link p){
	if(p){	
		printf("%d->",p->data);
		return OK;
	}else
		return ERROR;
}
void ListTraverse(LinkList L,Status(*visit)(Link p)){
	//依次对L中的每个元素调用函数visit,一旦visit失败,则操作失败
	Link p;
	p = L.head->next;//不带表头的输出
	while(p != NULL){
		visit(p);
	    p = p->next;
	}
	printf("\n");
}

------- 线性链表的其它操作 -------

23、逆位序创建带头结点的线性链表L ----回顶部

Status CreateList(LinkList &L){ 
	//逆位序创建一个带头结点的空单链表    
	int i;
	printf("input Length:");
	scanf("%d",&L.len);
	Link p;
	printf("input value with descend order!\n");
	for(i=L.len; i>0; --i){
		p = (Link)malloc(sizeof(LNode));
		scanf("%d",&p->data);
		p->next = L.head->next;
		L.head->next = p;   //头结点的指针永远指向最新的那一个结点 
	}
	p = L.head->next;
	while(p->next){
		p = p->next;
	}
	L.tail = p;
	return OK;
}

24、将线性链表按非递减有序排列 ----回顶部

void SortList(LinkList &L){//由低到高 
	Link p,q,r;
	ElemType t;
	for(p=L.head->next; p->next!=NULL; p=p->next)
	{
		r = p;//第一个结点的 指针 
		for(q=p->next; q!=NULL; q=q->next){
			if(q->data < r->data)
				r = q;
		}
		if(r != p){
			t = r->data;
			r->data = p->data;
			p->data = t;
		}
	}
}

25、往有序链表中插入元素e ----回顶部

Status OrderInsert(LinkList &L,ElemType e,int (*compare)(ElemType,ElemType)){ 
	// 已知L为有序线性链表,将元素e按非降序插入在L中。(用于一元多项式)
   	Link s,p,q;
   	q = L.head;
   	p = q->next;
   	while(p!=NULL && compare(p->data,e)<0){// p不是表尾且元素值小于e
     	q = p;
     	p = p->next;
   	}
   	s = (Link)malloc(sizeof(LNode)); // 生成结点
   	s->data = e; // 赋值
   	q->next = s; // 插入
   	s->next = p;
   	L.len++; // 表长加1
   	if(!p) // 插在表尾
     	L.tail = s; // 修改尾结点
   	return OK;
}

26、合并链表 ----回顶部

Status MergeList_L(LinkList La,LinkList Lb,LinkList &Lc){
	Link ha,hb,pa,pb,q;
	ElemType a,b;
	if(!InitList(Lc))
		return ERROR;
	ha = GetHead(La);hb = GetHead(Lb); //ha、hb分别指向 La、Lb的头结点
	pa = NextPos(La,ha);pb = NextPos(Lb,hb);//初始时刻 pa、pb分别指向La、Lb的首元结点
	while(pa && pb){
		a = GetCurElem(pa);b = GetCurElem(pb); //a、b分别是当前结点的值
		if((*compare)(a,b)<=0){ //当 a <= b时
			DelFirst(La,ha,q);  //删除 La的首元结点
			InsFirst(Lc,Lc.tail,q); //注意,此处为将q插入Lc的尾部
			pa = NextPos(La,ha); //pa指向La新的首元结点
		}else{
			DelFirst(La,hb,q);
			InsFirst(Lc,Lc.tail,q);
			pb = NextPos(Lb,hb);
		}
	}

	if(pa)
		Append(Lc,pa);
	else
		Append(Lc,pb);
	FreeNode(ha);
	FreeNode(hb);
	return OK;
}

27、用【头插法】逆置单链表 ----回顶部

//逆置单链表 (用头插法) 
void ReverseList(LinkList &L){
	LNode *p,*q;
	p = L.head->next;
	L.head->next = NULL;
	while(p!=NULL){
		q = p->next;
		p->next = L.head->next;
		L.head->next = p;
		p = q;
	}
}

参考文献
[1] 严蔚敏,吴伟民 ,《数据结构(C语言版)》.
[2] 程杰,《大话数据结构》,清华大学出版社,2011出版年.
[2] 明日科技,《C语言 从入门到精通》,清华大学出版社,2019年版

  • 1
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不动声色的小蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值