用算法实现:单链表和顺序表删除。删除顺序表中值相同的多余结点

求:单链表删除 和 顺序表删除的算法。删除表中值相同的多余结点 C++的
谢谢大家了

第8章排序(算法设计)习题练习答案
作者: 来源: http://www.csai.cn 2006年9月4日

13. 将哨兵放在R[n]中,被排序的记录放在R[0..n-1]中,重写直接插入排序算法。
解:
重写的算法如下:
void InsertSort(SeqList R)
{//对顺序表中记录R[0..n-1]按递增序进行插入排序
int i,j;
for(i=n-2;i>=0;i--) //在有序区中依次插入R[n-2]..R[0]
if(R[i].key>R[i+1].key) //若不是这样则R[i]原位不动
{
R[n]=R[i];j=i+1; //R[n]是哨兵
do{ //从左向右在有序区中查找插入位置
R[j-1]=R[j]; //将关键字小于R[i].key的记录向右移
j++;
}while(R[j].key<R[n].key]);
R[j-1]=R[n]; //将R[i]插入到正确位置上
}//endif
}//InsertSort.

14.以单链表作为存储结构实现直接插入排序算法。
解:
#define int KeyType //定义KeyType 为int型
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
struct node * next; //链表中指针域
}RecNode; //记录结点类型
typedef RecNode * LinkList ; //单链表用LinkList表示

void InsertSort(LinkList head)
{//链式存储结构的直接插入排序算法,head是带头结点的单链表
RecNode *p,*q,*s;
if ((head->next)&&(head->next->next))//当表中含有结点数大于1
{
p=head->next->next;//p指向第二个节点
head->next=NULL;
q=head;//指向插入位置的前驱节点
while(p)&&(q->next)&&(p->key<q->next->key)
q=q->next;
if (p)
{s=p;p=p->next;// 将要插入结点摘下
s->next=q->next;//插入合适位置:q结点后
q->next=s;
}
}
}

15.设计一算法,使得在尽可能少的时间内重排数组,将所有取负值的关键字放在所有取非负值的关键字之前。请分析算法的时间复杂度。
解:
因为只需将负数关键字排在前面而无需进行精确排列顺序,因此本算法采用两端扫描的方法,就象快速排序采用的方法一样,左边扫描到正数时停止,开始扫描右边,遇到负数时与左边的当前记录交换,如此交替进行,一趟下来就可以完成排序。

void ReSort(SeqList R)
{//重排数组,使负值关键字在前
int i=1,j=n; //数组存放在R[1..n]中
while (i<j) //i<j表示尚未扫描完毕
{ while(i<j&&R[i].key<0) //遇到负数则继续扫描
i++;
R[0]=R[i]; //R[0]为辅助空间
while(i<j&&R[j].key>=0)// 遇到正数则继续向左扫描
j--;
R[i++]=R[j];R[j--]=R[0];//交换当前两个元素并移动指针
}//endwhile
}//ReSort

本算法在任何情况下的比较次数均为n(每个元素和0)相比,交换次数少于n/2,总的来说,时间复杂度为O(n).

*16.写一个双向冒泡排序的算法,即在排序过程中交替改变扫描方向。
解:
算法如下:
void BubbleSort(SeqList R)
{//R[1..n]是待排序文件,双向扫描冒泡排序
int i,j,k;
Boolean exchange; //交换标记
i=n;j=1;
exchange=TRUE;
while (i>j)&&(exchange)
{k=i-1;exchange=FALSE;
while (k>=j)//由下往上扫描
{if (r[k]>r[k+1])
{r[0]=r[k];r[k]=r[k+1];r[k+1]=r[k];exchange=TRUE;//交换
}//endif
k--;
}//endwhile
if (exchange)
{exchange=FALSE;
j++;k=j+1;
while(k<=i)//由上往下扫描
{if (r[k]<r[k-1])
{r[0]=r[k];r[k]=r[k-1];r[k-1]=r[k];exchange=TRUE;//交换
}//endif
k++;
}endwhile
i--;
}//endif
}endwhile
}//endsort

17.下面是一个自上往下扫描的冒泡排序的伪代码算法,它采用lastExchange 来记录每趟扫描中进行交换的最后一个元素的位置,并以它作为下一趟排序循环终止的控制值。请仿照它写一个自下往上扫描的冒泡排序算法。
void BubbleSort(int A[],int n)
//不妨设A[0..n-1]是整型向量
int lastExchange,j,i=n-1;
while (i>0)
lastExchange=0;
for(j=0;j<i;j++)//从上往下扫描A[0..i]
if(A[j+1]<A[j]){
交换A[j]和A[j+1];
lastExchange=j;
}
i=lastExchange;//将i置为最后交换的位置
}//endwhile
}//BubbleSort

解:算法如下:
void BubbleSort(int A[],int n)
//不妨设A[0..n-1]是整型向量
int lastExchange,j,i=0;
while (i<n) //这一条很重要,如不改为这样,算法将无限循环下去
lastExchange=n;
for(j=n-1;j>i;j--)//从下往上扫描A[0..i]
if(A[j-1]<A[j]){
交换A[j]和A[j-1];
lastExchange=j;
}
i=lastExchange;//将i置为最后交换的位置
}//endwhile
}//BubbleSort

18.改写快速排序算法,要求采用三者取中的方式选择划分的基准记录;若当前被排序的区间长度小于等于3时,无须划分而是直接采用直接插入方式对其排序。
解:
改写后的算法如下:
void QuickSort(SeqList R,int low ,int high)
{//对R[low..high]快速排序
int pivotpos;
if(high-low<=2)//若当前区内元素少于3个
{//则进行直接插入排序
InsertSort(R,low,high);
}
else
{
pivotpos=midPartion(R,low,high);
QuickSort(R,low,pivotpos-1);
QuickSort(R,pivotpos+1,high);
}
}//QuickSort

int midPartion(SeqList R,int i, int j)
{//三者取中规则定基准
if(R[(i+j)/2].key>R[i].key)
{ 交换R[(i+j)/2]和R[i];}
if(R[i].key>R[j].key)
{ 交换R[i]和R[j];}
if(R[i].key)<R[(i+j)/2].key)
{ 交换R[i]和R[(i+j)/2];}
//以上三个if语句就使区间的第一个记录的key值为三个key的中间值
return Partion(R,i,j);//这样我们就可以仍使用原来的划分算法了
}

19.对给定的j(1≤j≤n ),要求在无序的记录区R[1..n]中找到按关键字自小到大排在第j个位置上的记录(即在无序集合中找到第j个最小元),试利用快速排序的划分思想编写算法实现上述的查找操作。
答:
int QuickSort(SeqList R,int j,int low,int high)
{ //对R[low..high]快速排序
int pivotpos; //划分后的基准记录的位置
if(low<high){//仅当区间长度大于1时才须排序
pivotpos=Partition(R,low,high); //对R[low..high]做划分
if (pivotpos==j) return r[j];
else if (pivotpos>j) return(R,j,low,pivotpos-1);
else return quicksort(R,j,pivotpos+1,high);
}
} //QuickSort

20.以单链表为存储结构,写一个直接选择排序算法。
答:
#define int KeyType //定义KeyType 为int型
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
struct node * next; //链表中指针域
}RecNode; //记录结点类型

typedef RecNode * LinkList ; //单链表用LinkList表示

void selectsort(linklist head)
{RecNode *p,*q,*s;
if(head->next)&&(head->next->next)
{p=head->next;//p指向当前已排好序最大元素的前趋
while (p->next)
{q=p->next;s=p;
while(q)
{if (q->key<s->key) s=q;
q=q->next;
}//endwhile
交换s结点和p结点的数据;
p=p->next;
}//endwhile
}//endif
}//endsort

21.写一个heapInsert(R,key)算法,将关键字插入到堆R中去,并保证插入R后仍是堆。提示:应为堆R增加一个长度属性描述(即改写本章定义的SeqList类型描述,使其含有长度域);将key先插入R中已有元素的尾部(即原堆的长度加1的位置,插入后堆的长度加1),然后从下往上调整,使插入的关键字满足性质。请分析算法的时间。
答:
#define n 100//假设文件的最长可能长度
typedef int KeyType; //定义KeyType 为int型
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
}Rectype; //记录结点类型

typedef struct{
Rectype data[n] ; //存放记录的空间
int length;//文件长度
}seqlist;

void heapInsert(seqlist *R,KeyType key)
{//原有堆元素在R->data[1]~R->data[R->length],
//将新的关键字key插入到R->data[R->length+1]位置后,
//以R->data[0]为辅助空间,调整为堆(此处设为大根堆)
int large;//large指向调整结点的左右孩子中关键字较大者
int low,high;//low和high分别指向待调整堆的第一个和最后一个记录
int i;
R->length++;R->data[R->length].key=key;//插入新的记录
for(i=R->length/2;i>0;i--)//建堆
{
low=i;high=R->length;
R->data[0].key=R->data[low].key;//R->data[low]是当前调整的结点
for(large=2*low;large<=high;large*=2){
//若large>high,则表示R->data[low]是叶子,调整结束;
//否则令large指向R->data[low]的左孩子
if(large<high&&R->data[large].key<R->data[large+1].key)
large++;//若R->data[low]的右孩子存在
//且关键字大于左兄弟,则令large指向它
if (R->data[0].key<R->data[large].key)
{ R->data[low].key= R->data[large].key;
low=large;//令low指向新的调整结点
}
else break;//当前调整结点不小于其孩子结点的关键字,结束调整
}//endfor
R->data[low].key=R->data[0].key;//将被调整结点放入最终的位置上
}//end of for
}end of heapinsert

算法分析:
设文件长度为n,则该算法需进行n/2趟调整,总的时间复杂度与初建堆类似,最坏时间复杂度为O(nlgn),辅助空间为O(1).

22.写一个建堆算法:从空堆开始,依次读入元素调用上题中堆插入算法将其插入堆中。
答:
void BuildHeap(seqlist *R)
{
KeyType key;
R->length=0;//建一个空堆
scanf("%d",&key);//设MAXINT为不可能的关键字
while(key!=MAXINT)
{
heapInsert(R,key);
scanf("%d",&key);
}
}

23.写一个堆删除算法:HeapDelete(R,i),将R[i]从堆中删去,并分析算法时间,提示:先将R[i]和堆中最后一个元素交换,并将堆长度减1,然后从位置i开始向下调整,使其满足堆性质。
答:
void HeapDelete(seqlist *R,int i)
{//原有堆元素在R->data[1]~R->data[R->length],
//将R->data[i]删除,即将R->data[R->length]放入R->data[i]中后,
//将R->length减1,再进行堆的调整,
//以R->data[0]为辅助空间,调整为堆(此处设为大根堆)
int large;//large指向调整结点的左右孩子中关键字较大者
int low,high;//low和high分别指向待调整堆的第一个和最后一个记录
int j;
if (i>R->length)
Error("have no such node");
R->data[i].key=R->data[R->length].key;
R->length--;R->data[R->length].key=key;//插入新的记录
for(j=i/2;j>0;j--)//建堆
{
low=j;high=R->length;
R->data[0].key=R->data[low].key;//R->data[low]是当前调整的结点
for(large=2*low;large<=high;large*=2){
//若large>high,则表示R->data[low]是叶子,调整结束;
//否则令large指向R->data[low]的左孩子
if(large<high&&R->data[large].key<R->data[large+1].key)
large++;//若R->data[low]的右孩子存在
//且关键字大于左兄弟,则令large指向它
if (R->data[0].key<R->data[large].key)
{ R->data[low].key= R->data[large].key;
low=large;//令low指向新的调整结点
}
else break;//当前调整结点不小于其孩子结点的关键字,结束调整
}//endfor
R->data[low].key=R->data[0].key;//将被调整结点放入最终的位置上
}//end of for
}end of HeapDelete

24.已知两个单链表中的元素递增有序,试写一算法将这两个有序表归并成一个递增有序的单链表。算法应利用原有的链表结点空间。
答:
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
struct node * next; //链表中指针域
}RecNode; //记录结点类型

typedef RecNode * LinkList ; //单链表用LinkList表示

void mergesort(LinkList la,LinkList lb,LinkList lc)
{RecNode *p,*q,*s,*r;
lc=la;
p=la;//p是la表扫描指针,指向待比较结点的前一位置
q=lb->next;//q是lb表扫描指针,指向比较的结点
while(p->next)&&(q)
if (p->next->key<=q->key)
p=p->next;
else {s=q;q=q->next;
s->next=p->next;p->next=s;//将s结点插入到p结点后
p=s;}
if (!p->next) p->next=q;
free(lb);
}

25.设向量A[0..n-1]中存有n个互不相同的整数,且每个元素的值均在0到n-1之间。试写一时间为O(n)的算法将向量A排序,结果可输出到另一个向量B[0..n-1]中。
答:
sort(int *A,int *B)
{//将向量A排序后送入B向量中
int i;
for(i=0;i<=n-1;i++)
B[A[i]]=A[i];
}

*26.写一组英文单词按字典序排列的基数排序算法。设单词均由大写字母构成,最长的单词有d个字母。提示:所有长度不足d个字母的单词都在尾处补足空格,排序时设置27个箱子,分别与空格,A,B...Z对应。
答:
#define KeySize 10 //设关键字位数d=10
#define Radix 27 //基数rd为27
typedef RecType DataType;//将队列中结点数据类型改为RecType类型
typedef struct node{
char key[KeySize]; //关键字域
OtherInfoType info; //其它信息域,
}RecType; //记录结点类型
typedef RecType seqlist[n+1];

void RadixSort(seqlist R)
{
LinkQueue B[Radix];
int i;
for(i=0;i<Radix;i++)//箱子置空
InitQueue(&B[i]);
for(i=KeySize-1;i>=0;i--){//从低位到高位做d趟箱排序
Distribute(R,B,i);//第KeySize-i趟分配
Collect(R,B);//第KeySize-i趟收集
}
}

void Distribute(seqlist R,LinkQueue B[], int j)
{//按关键字的第j个分量进行分配,初始时箱子为空
int i;
j=KeySize-j; // 确定关键字从低位起的位置
for(i=0;i<n;i++) //依次扫描R[i],将其装箱
if (R[i].key[j]-'A'>26)
EnQueue(&B[0],R[i]);//将第j位关键字位空格的记录入第0个队列
else EnQueue(&B[0],R[R[i].key[j]-'A'+1]);
}

void Collect(seqlist R,LinkQueue B[])
{
//依次将各非空箱子中的记录收集起来,本过程结束,各箱子都变空
int i,j;
for (j=0;j<Radix;j++)
while(!QueueEmpty(&B[j]))
R[i++]=DeQueue(&B[j]);//将出队记录依次输出到R[i]中
}
温馨提示:答案为网友推荐,仅供参考
第1个回答  2007-01-05
第一总算法
设两个指针p,q
p<-head
repeat
{
q<-p.next
repeat
{
if (p.data=q.data) { k<-q.next;del(q);q<-k;}
else q<-q.next
}until q=nul
p<-p.next
}until (p=null) or (p.next=null)
时间为O(n*n) 空间O(1)
还有一种算法
设一个指针p
数组 hash[1..maxnumber] as type byte
p<-head
repeat
{
if (hash[p.data]=1 ) { k<-p.next;del(p);p<-k;} else {hash[p.data]<-1; p<-p.next}
}until p=null
时间为O(n) 空间O(m)
相似回答