首页 > 其他分享 >数据结构(借鉴408)-线性表

数据结构(借鉴408)-线性表

时间:2023-02-24 13:24:10浏览次数:39  
标签:结点 return 线性表 LNode int next 数据结构 data 408

数据结构

  1. 逻辑结构、物理结构
  2. 时间复杂度、空间复杂度

线性表

顺序表

#define MAX_SIZE 100
typedef int ElemType;
typedef struct seqlist{
	ElemType data[MAX_SIZE];
	int length;
}SeqList

//初始化
SeqList* L->data = (SeqList*)malloc(sizeof(Elemtype)*MAX_SIZE);

//查找
int FindByValue(SeqList* L, int e){
	int i;
	for(i=0;i<L->length;i++){
		if(L->data[i] == e)
			return i+1;
	}
	return -1;
}

//插入
bool ListInsert(SeqList*L, int i, int e){
	if(i<1 || i>L->length+1) return false;
	if(L->length >= MAX_SIZE) return false;
	for(int j = L->length;j>=i;j--){
		L->data[j] = L->data[j-1];
	}
	L->data[i-1] = e;
	L->length++;
	return true;
}


//删除
bool ListDelete(SeqList*L, int i, int* e){
	if(L->length == 0) return false;
	if(i<1 || i>L->length) return false;
	e = L->data[i-1];
	for(int j=i;j<L->length;j++){
		L->data[j-1] = L->data[j];
	}
	L->length--;
	return true;
}

1.编写算法,将两个非递减有序顺序表A和B合并成一个新的非递减有序顺序表C,已知顺序表A和B的元素个数分别为m和n。其中顺序表采用动态分配空间,定义如下。

Typedef struct{
	Elemtype * elem; //存储空间基地址
	int length;		//当前长度
	int listsize;	//当前分配的存储容量
}SeqList;

算法思想:【双指针不回溯】
要合并两个有序的顺序表A和B,那么需要开辟一个新的数组空间C,当A和B都未到末尾时,挨个比较A和B的元素,将小元素放入到C中,当元素相等时,只保留一个。当A或B结束时,将未结束表的元素逐个放入到C中。

void Combination(SeqList &L1,SeqList &L2, SeqList &L3){
	int i=0,j=0,k=0;
	while((i!=L1->length)&&(j!=L2->length){
		if(L1->data[i]>L2->data[j]){
			L3->data[k++]=L2->data[j++];//L1中元素大,合并L2中元素到L3中
		}
		else if(L1->data[i]==L2->data[j]){
			L3->data[k++]=L2->data[j++];//元素相等,只保留一个,合并到L3中
			i++;
		}
		else{
			L3->data[k++]=L1->data[i++];//L2中元素大,合并L1中元素到L3中
		}
		L3->length++;
	}

	while(i<L1->length){ //L2结束,合并L1中的元素到L3中
		L3->data[k++]=L1->data[i++];
		L3->length++;
	}
	while(j<L2->length){ //L1结束,合并L2中的元素到L3中
		L3->data[k++]=L2->data[j++];
		L3->length++;
	}
}

2.试写一算法,实现顺序表的就地逆置,即利用原表的存储空间将线性表(a1,a2,a3,...,an-1,an)->(an,an-1,...,a3,a2,a1)。

算法思想:【逆置】要实现数组的逆置,且要求使用原有空间,只需要将对应的数组元素位置交换就可以,如第1个(对应下标是0)和第n个(对应下标是n-1)交换,第2个(对应下标是1)和第n-1个(对应下标是n-2)交换,需要交换的连个元素的下标之和是n-1,其中n是表长。

int ListOppose(SeqList &L){
	int i;
	ElemType x;
	//只需要遍历原表的一半就可以实现数据元素位置的交换
	for(i=0; i<L->length/2; i++){
		x = L->data[i];
		L->data[i] = L->data[L->length-i-1]; //数据元素交换 -> 逆置
		L->data[L->length-i-1]=x;
	}
	
	return 1;
}

3.一个线性表中的元素全部为正或负整数,试设计一算法,再尽可能少的时间内重排该表,将正、负整数分开,使线性表中所有负整数在正整数前面。

算法思想:【快速排序】
算法中提出暂存的第一个元素不作为比较的标准,比较的标准是0,判断对应的元素是否是正数或者负数。

int ReArrange(SeqList &a, int n){
	int low=0,high=n-1;
	int t=a[low];	//枢轴元素,只是暂存,不作为比较对象
	while(low<high){
		while(low<high&&a[high]>=0) //寻找小于0的元素
			high--;
		a[low]=a[high];
		while(low<high&&a[low]<0)	//寻找大于0的元素
			low++;
		a[high]=a[low];
	}
	a[low]=t;	//将枢轴元素放到最终位置
	return 1;
}

4.已知线性表(a1,a2,a3,...,an-1,an)按顺序结构存储且每个元素为不相等的整数。设计把所有奇数移到所有偶数前边的算法(要求时间最少,辅助空间最少)

算法思想:【快排】
通过对数字模2是否等于0进行判断,使得奇数元素都在左边,偶数元素都在右边。
具体方法:设置两个指针变量分别指向表头和表尾,它们分别向中间移动,指向表头的数组指针如果遇到偶数且指向标为的数组指针遇到奇数,则互相交换,然后继续移动直至两者相遇。

void part(int arry[], int n){
	int i,j.temp;
	i=0,j=n-1;
	while(i<j){
		while(i<j&&array[i]%2 != 0) //i指针从前往后扫描数组,遇到偶数停下
			i++;
		while(i<j&&array[j]%2 == 0) //j指针从后往前扫描数组,遇到奇数停下
			j--;
		if(i<j){  //如果i<j,交换两个指针分别指向的元素
			temp = array[i];
			array[i] = array[j];
			array[j] = temp;
		}
	}
}

5.已知在一维数组A[1,...,m+n+1]中依次存放着连个顺序表:(a1,a2,a3,...,am)和(b1,b2,b3,...,an)。试编写程序,将数组中凉饿顺序表的位置互换,即将(b1,b2,b3,...,an)放在(a1,a2,a3,...,am)的前面。

算法思想:
第一步:将A中所有元素逆置,变成bn,bn-1,...,b1,am,am-1,...,a1。
第二步:将前n个逆置
第三步:将后m个逆置

void Reserve(ElemType A[], int left, int right, int arraySize){
	if(left>=right || right>=arraySize)
		return;
	int mid =(left+right)/2;
	for(int i=0; i<=mid-left; i++){
		ElemType temp = A[left+i];
		A[left+i] = A[right-i];
		A[right-i] = temp;
	}
}

void Exchange(ElemType A[], int m, int n, int arraySize){
	Reserve(A,0,m+n-1,arraySize);
	Reserve(A,0,n-1,arraySize);
	Reserve(A,n,m+n-1,arraySize);
}

6.设有一个线性表存放在一维数组a[0,...,n-1]中,编程将数组中每个元素循环右移k位,要求只用一个辅助单元,时间复杂度为O(n)。

void Reserve(int* array, int p, int q){
	for(; p<q; p++,q--){
		int temp = array[q];
		array[q] = array[p];
		array[p] = temp;
	}
}

void RightShift(int* array, int n, int k){
	k%=n;
	Reserve(array,0,n-1);
	Reserve(array,0,n-1-k);
	Reserve(array,n-k,n-1);
}

单链表

typedef struct LNode{
	ElemType data;
	struct LNode* next;
}LNode, *LinkList;

//结点创建
LNode *p;
p=(LNode*) malloc(sizeof(LNode));
p->data = 20;
p->next = NULL; 

//添加q
q->next = p->next;
p->next = q;

//删除p的直接后继
q=p->next;
p-next =q->next;
free(q); 
  • 头插法 单链表逆序 头指针(不是数据结点)

  • 尾插法 单链表顺序 尾指针(数据结点)

      //头插法
    

    LinkList Creat_list(LinkList head){
    head = (LinkList)malloc(sizeof(LNode)); //为头指针开辟内存空间
    LNode *node = NULL; //定义工作指针
    head->next = NULL;
    node = head->next; //将最后一个结点的指针域永远保持为NULL

      int count=0;		//创建结点的个数
      scanf("%d", &count);
      for(int i=0; i<count; i++){
      	node = (LNode*)malloc(sizeof(LNode)); //为新结点开辟内存空间
      	node->data = i;						  //为新结点的数据域赋值
      	node->next = head->next;//将头指针所指向的下一个结点的地址,赋值个新创建的结点的next
      	head->next = node;		//将新创建的结点的地址赋值个头指针的下一个结点
      }
      return head;	
    

    }

    //尾插法
    LinkList Creat_list(LinkList head){
    head = (LinkList)malloc(sizeof(LNode)); //为头指针开辟内存空间
    LNode *node = NULL; //定义工作指针
    LNode *end = NULL; //定义尾指针
    head->next = NULL; //初始化头结点知道的下一个地址为NULL
    end = head; //未创建其余结点之前,只有一个头结点

      int count=0;		//创建结点的个数
      scanf("%d", &count);
      for(int i=0; i<count; i++){
      	node = (LNode*)malloc(sizeof(LNode)); //为新结点开辟内存空间
      	node->data = i;						  //为新结点的数据域赋值
      	end->next = node;	//新结点赋值给end的下一个
      	end = node; 		//新结点成为新的尾结点
      }
      end->next = NULL;
      return head;
    

    }

    //查找
    bool GetElem_L(LinkList &L, int i, ElemType &e){
    //L为带头结点的单链表的头指针
    //当第i个元素存在时,其值赋值给e并返回true,否则返回false
    LNode *p = L->next;
    int j = 1;
    while(p && j<i){
    p = p->next;
    ++j;
    }
    if(!p || j>i) return false;
    e = p->data;
    return true;
    }

    LNode Locate_Node(LNode L, int key){
    /
    在以L为头结点的单链表中查找值为key的第一个结点
    /
    LNode * p = L->next; //p指向第一个数据结点
    while(p!=NULL && p->data != key)
    p = p->next;

      if(p->data == data)
      	return p;
      else{
      	printf("No Result.\n");
      	return NULL;
      }
    

    }

    //插入
    bool ListInsert_L(LinkList &L, int i, ElemType e){
    //在带头结点的单链线性表L中第i个位置之前插入元素e
    LNode *p = L;
    int j=0;
    while(p && j<i-1){ //寻找第i-1个结点的位置的过程
    p = p->next;
    ++j;
    } //寻找第i-1个结点
    if(!p ||j>i-1) return false;

      //执行插入操作
      LNode *s;
      s=(LinkList)malloc(sizeof(LNode));
      s->data = e;
      s->next = p->next;
      p->next = s;
      return true;
    

    }

    //删除
    bool ListDelete_L(LinkList &L, int i, ElemType &e){
    //在带头结点的单链表L中,删除第i个元素,并由e返回其值
    LNode *p;
    LNode *q;
    p=L;
    int j=0;
    while(p->next && j<i-1){ // 寻找第i个结点,并令p指向其前驱
    p = p->next;
    ++j;
    }
    if(!(p->next) || j>i-1) return false; //删除位置不合理
    q=p->next;
    p->next = q->next; //删除并释放结点
    e=q->data;
    free(q);
    return true;
    }

    void Delete_LinkList(LNode *L, int key){
    //删除以L为头结点的单链表中值为key的第一个结点
    LNode *p = L, *q=L->next;
    while(q!=NULL && q->data!=key){
    p=q;
    q=q->next;
    }
    if(q->data == key){
    p->next = q->next;
    free(q);
    }
    else printf("NULL\n");
    }

    //从头到尾依次遍历,输出各个元素的值
    void printL(LinkList L){
    LNode *p;
    p=L->next;
    while(p!=NULL){
    printf("%d ",p->data);
    p=p->next;
    }
    }

1.给定键值按升序排列的带头结点的单链表La和Lb,将其合并成升序排列的单链表,并返回新链表的表头指针。要求利用原表的结点数据空间。

算法分析:若La、Lb两个链表的长度分别为m,n,则合并链表的时间复杂度为O(m+n)。

LNode *Merge_LinkList(LNode *La, LNode *Lb){
	//合并以La和Lb为头结点的两个有序链表
	LNode *Lc,*pa,*pb,*pc,*ptr;
	Lc=La;
	pc=La;
	pa=La->next;
	pc=Lb->next;
	whlile(pa!=NULL && pb!=NULL){
		if(pa->data < pb->data){  //将pa所指的结点合并,pa指向下一个结点
			pc->next = pa;
			pc=pa;
			pa=pa->next;
		}
		if(pa->data > pb->data){  //将pb所指的结点合并,pb指向下一个结点
			pc->next = pb;
			pc=pb;
			pb=pb->next;
		}
		if(pa->data == pb->data){  //将pb所指的结点合并,pb所指结点删除
			pc->next = pa;
			pc=pa;
			pa=pa->next;
			ptr=pb;
			pb=pb->next;
			free(ptr);
		}
	
		if(pa!=NULL)               //将剩余结点链接上 
			pc->next = pa;  
		else 
			pc->next = pb;   
		free(Lb);
		return Lc;
	}
}

2.删除单链表中所有值重复的结点,使得所有结点的值都不相同

基本思想:从单链表的第一个结点开始,对每个结点进行检查,检查链表中的结点的所有后继结点,只要有结点的值和该结点的值相同,就删除;然后检查下一个结点,直到所有的结点都检查过。

void Delte_Node_vale(LNode *L){   //时间复杂度O(n2) 空间复杂度O(1)
//删除以L为头结点的单链表中所有值相同的结点
	LNode *p=L->next, *q, *ptr;  //q是被删除结点的直接前驱 ptr是被删除元素
	while(p!=NULL){
		q=p;
		ptr=p->next;
		
		//检查结点p的所有后继结点ptr
		while(ptr!=NULL){
			if(ptr->data == p->data){
				q->next = ptr->next;
				free(ptr);
				ptr=q->next;
			}
			else{
				q=ptr;
				ptr=ptr->next;
			}
		}

		p=p->next;
	}
}

//其他方法:借助Hash,用空间换时间

3.试写出逆转线性单链表的算法,单链表结点的类型定义如下

typedef struct node{
	ElemType data;
	struct node* next;
}LNode,*LinkList;

基本思想:采用头插法,以此借助原有结点的存储空间建立新的单链表

LNode *revert_list(LNode* head){
	if(NULL == head)
		return head;
	LNode *p = head->next;
	head->next = NULL;
	LNode *tmp = NULL;
	while(p){
		tmp = p->next;
		p->next = head->next; //头插法
		head->next = p;
		p=tmp;
	}

	return head;
}

标签:结点,return,线性表,LNode,int,next,数据结构,data,408
From: https://www.cnblogs.com/yongchao/p/17151060.html

相关文章